Plugin Directory

Changeset 1504964


Ignore:
Timestamp:
09/29/2016 07:55:29 AM (10 years ago)
Author:
spindogs
Message:

release v1.1.2

Location:
wp-platform/trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • wp-platform/trunk/classes/Form.php

    r1491184 r1504964  
    44class Form {
    55
    6     protected $uniquevar;
    7     protected $is_submitted;
    8     protected $has_success;
    9     protected $values = array();
    10     protected $fields = array();
    11     protected $hidden = array();
    12     protected $errors = array();
    13     protected $inputs = array();
    14     protected $html = array();
    15 
    16     public $require_all = true;
    17     public $action;
    18     public $method = 'post';
    19     public $form_id;
    20     public $form_class;
    21     public $error_class = 'error';
    22     public $error_wrap = 'error_feedback';
    23     public $field_wrap = 'field_wrap';
    24     public $label_wrap = 'label_wrap';
    25     public $input_wrap = 'input_wrap';
    26     public $submit_wrap = 'submit_wrap';
    27     public $required_wrap = 'required';
    28     public $sublabel_wrap = 'sublabel_wrap';
    29     public $helper_wrap = 'helper_wrap';
    30     public $keep_gets = true;
    31     public $placeholder_all = false;
    32     public $placeholders = array();
    33     public $labels = array();
    34     public $sublabels = array();
    35     public $helpers = array();
    36     public $fragment;
    37 
    38     /**
    39      * @return mixed
    40      */
    41     public function __get($name)
    42     {
    43         return $this->{$name};
    44     }
    45 
    46     /**
    47      * @param string $uniquevar
    48      * @return void
    49      */
    50     public function __construct($uniquevar='posted')
    51     {
    52 
    53         $this->action = URI;
    54         $this->uniquevar = $uniquevar;
    55         $this->form_id = $uniquevar;
    56         $this->hidden($this->uniquevar, 1);
    57 
    58         unset($this->values[$this->uniquevar]);
    59 
    60         if (isset($_REQUEST[$this->uniquevar]) && $_REQUEST[$this->uniquevar] == 1) {
    61             $this->is_submitted = true;
    62             $this->has_success = true; //this gets set false if we hit an error
    63         }
    64 
    65     }
    66 
    67     /**
    68      * @param array $params
    69      * @return void
    70      */
    71     public function addField($name, $params)
    72     {
    73         $defaults = array(
    74             'type' => '',
    75             'label' => '',
    76             'options' => array(),
    77             'initial' => '',
    78             'required' => NULL,
    79             'attrs' => array()
    80         );
    81 
    82         $params = array_merge($defaults, $params);
    83 
    84         if (isset($params['name'])) {
    85             unset($params['name']);
    86         }
    87 
    88         $this->fields[$name] = $params;
    89     }
    90 
    91     /**
    92      * @param string $name
    93      * @param array $params
    94      * @return void
    95      */
    96     protected function addInput($name, $params)
    97     {
    98         $initial = $params['initial'];
    99 
    100         if (!$this->submitted()) {
    101             $value = $initial;
    102         } elseif (isset($_REQUEST[$name])) {
    103             $value = $_REQUEST[$name];
    104         } else {
    105             $value = '';
    106         }
    107 
    108         $this->addField($name, $params);
    109         $this->setValue($name, $value);
    110 
    111         $type = $params['type'];
    112         $label = $params['label'];
    113         $required = $this->isRequired($name);
    114         $attrs = $params['attrs'];
    115         $attrs = $this->filterAttrs($attrs, $name);
    116 
    117         if ($this->submitted()) {
    118 
    119             if ($required && $value == '') {
    120                 $this->error($label.' not provided', $name);
    121             } elseif ($type == 'text' && isset($attrs['limit']) && strlen($value) > $attrs['limit']) {
    122                 $this->error('Cannot enter more than '.$attrs['limit'].' characters', $name);
    123             }
    124 
    125         }
    126 
    127         $input = '<input ';
    128         $input .= 'type="'.$type.'" ';
    129         $input .= 'name="'.$name.'" ';
    130         $input .= 'id="{input_id}" ';
    131         $input .= 'value="'.self::esc_html($value).'" ';
    132         $input .= 'class="{error}" ';
    133         $input .= self::make_attr('placeholder', $attrs);
    134         $input .= self::make_attr('readonly', $attrs);
    135         $input .= self::make_attr('disabled', $attrs);
    136         $input .= self::make_attr('autocomplete', $attrs);
    137         $input .= self::make_attr('step', $attrs);
    138         $input .= self::make_attr('min', $attrs);
    139         $input .= self::make_attr('max', $attrs);
    140         $input .= '>';
    141 
    142         $this->inputs[$name] = $input;
    143 
    144     }
    145 
    146     /**
    147      * @param string $name
    148      * @param array $params
    149      * @return void
    150      */
    151     protected function addSingular($name, $params)
    152     {
    153         $initial = $params['initial'];
    154         $label = $params['label'];
    155 
    156         if (!$this->submitted()) {
    157             $value = $initial;
    158         } else if (isset($_REQUEST[$name])) {
    159             $value = $_REQUEST[$name];
    160         } else {
    161             $value = '';
    162         }
    163 
    164         if (!$value) {
    165             $value = ''; //convert all types of false to string
    166         }
    167 
    168         $this->addField($name, $params);
    169         $this->setValue($name, $value);
    170 
    171         $required = $this->isRequired($name);
    172 
    173         if ($this->submitted()) {
    174 
    175             if ($required && !$value) {
    176                 $this->error($label.' not provided', $name);
    177             }
    178 
    179         }
    180 
    181     }
    182 
    183     /**
    184      * @param string $name
    185      * @param array $params
    186      * @return void
    187      */
    188     protected function addMulti($name, $params)
    189     {
    190         $initial = $params['initial'];
    191         $label = $params['label'];
    192 
    193         if (!$this->submitted()) {
    194             $value = (array)$initial;
    195         } elseif (isset($_REQUEST[$name])) {
    196             $value = $_REQUEST[$name];
    197         } else {
    198             $value = array();
    199         }
    200 
    201         $this->addField($name, $params);
    202         $this->setValue($name, $value);
    203 
    204         $required = $this->isRequired($name);
    205 
    206         if ($this->submitted()) {
    207 
    208             if ($required && count($this->values[$name]) < 1) {
    209                 $this->error($label.' not provided', $name);
    210             }
    211 
    212         }
    213 
    214     }
    215 
    216     /**
    217     * @param string $name
    218     * @param string $value
    219     * @return void
    220     */
    221     public function hidden($name, $value)
    222     {
    223 
    224         if ($this->is_submitted && isset($_REQUEST[$name])) {
    225             $value = $_REQUEST[$name];
    226         }
    227 
    228         $this->hidden[$name] = $value;
    229         $this->values[$name] = $value;
    230 
    231     }
    232 
    233     /**
    234      * @param string $name
    235      * @param string $label
    236      * @param string $initial
    237      * @param bool $required
    238      * @param array $attrs
    239      * @return void
    240     */
    241     public function text($name, $label, $initial='', $required=NULL, $attrs=array())
    242     {
    243         $params = get_defined_vars();
    244         $params['type'] = __FUNCTION__;
    245         $this->addInput($name, $params);
    246     }
    247 
    248     /**
    249      * @param string $name
    250      * @param string $label
    251      * @param string $initial
    252      * @param bool $required
    253      * @param array $attrs
    254      * @return void
    255     */
    256     public function textarea($name, $label, $initial='', $required=NULL, $attrs=array())
    257     {
    258 
    259         $params = get_defined_vars();
    260         $params['type'] = __FUNCTION__;
    261         $this->addInput($name, $params);
    262 
    263         $attrs = $this->filterAttrs($attrs, $name);
    264         $value = $this->getValue($name);
    265 
    266         $input = '<textarea ';
    267         $input .= 'name="'.$name.'" ';
    268         $input .= 'id="{input_id}" ';
    269         $input .= 'class="{error}" ';
    270         $input .= self::make_attr('placeholder', $attrs);
    271         $input .= self::make_attr('readonly', $attrs);
    272         $input .= self::make_attr('disabled', $attrs);
    273         $input .= self::make_attr('rows', $attrs);
    274         $input .= self::make_attr('cols', $attrs);
    275         $input .= '>';
    276         $input .= self::esc_html($value);
    277         $input .= '</textarea>';
    278 
    279         $this->inputs[$name] = $input;
    280 
    281     }
    282 
    283     /**
    284      * @param string $name
    285      * @param string $label
    286      * @param array $options
    287      * @param string $initial
    288      * @param bool $required
    289      * @param array $attrs
    290      * @return void
    291     */
    292     public function select($name, $label, $options, $initial=false, $required=NULL, $attrs=array())
    293     {
    294         $params = get_defined_vars();
    295         $params['type'] = __FUNCTION__;
    296         $attrs = $this->filterAttrs($attrs, $name);
    297 
    298         if (empty($attrs['is_multi'])) {
    299             $this->addSingular($name, $params);
    300             $is_multi = false;
    301             $multiple = '';
    302             $input_name = $name;
    303         } else {
    304             $this->addMulti($name, $params);
    305             $is_multi = true;
    306             $multiple = ' multiple="multiple"';
    307             $input_name = $name.'[]';
    308         }
    309 
    310         $value = $this->getValue($name);
    311 
    312         $input = '<select name="'.$input_name.'" ';
    313         $input .= 'id="{input_id}" ';
    314         $input .= 'class="{error}" ';
    315         $input .= $multiple;
    316         $input .= '>';
    317         $input .= "\n";
    318 
    319         if (!isset($attrs['first_option'])) {
    320             $input .= '<option value="0">[please select]</option>';
    321             $input .= "\n";
    322         } elseif ($attrs['first_option']) {
    323             $input .= '<option value="0">'.$attrs['first_option'].'</option>';
    324             $input .= "\n";
    325         }
    326 
    327         foreach ($options as $key => $text) {
    328 
    329             if (is_array($text)) { //optgroups
    330 
    331                 $input .= '<optgroup label="'.$key.'">'."\n";
    332 
    333                 foreach ($text as $key => $text) {
    334 
    335                     if ($is_multi && in_array($key, $value)) {
    336                         $selected = ' selected="selected"';
    337                     } elseif ($key == $value) {
    338                         $selected = ' selected="selected"';
    339                     } else {
    340                         $selected = '';
    341                     }
    342 
    343                     if (isset($attrs['disabled']) && in_array($key, $attrs['disabled'])) {
    344                         $disabled = ' disabled="disabled"';
    345                     } else {
    346                         $disabled = '';
    347                     }
    348 
    349                     $input .= '<option value="'.$key.'" '.$selected.$disabled.'>'.$text.'</option>';
    350                     $input .= "\n";
    351 
    352                 }
    353 
    354                 $input .= '</optgroup>';
    355                 $input .= "\n";
    356 
    357             } else {
    358 
    359                 if ($is_multi && in_array($key, $value)) {
    360                     $selected = ' selected="selected"';
    361                 } elseif ($key == $value) {
    362                     $selected = ' selected="selected"';
    363                 } else {
    364                     $selected = '';
    365                 }
    366 
    367                 if (isset($attrs['disabled']) && in_array($key, $attrs['disabled'])) {
    368                     $disabled = ' disabled="disabled"';
    369                 } else {
    370                     $disabled = '';
    371                 }
    372 
    373                 $input .= '<option value="'.$key.'" '.$selected.$disabled.'>'.$text.'</option>';
    374                 $input .= "\n";
    375 
    376             }
    377 
    378         }
    379 
    380         $input .= '</select>';
    381 
    382         $this->inputs[$name] = $input;
    383 
    384     }
    385 
    386     /**
    387      * @param string $name
    388      * @param string $label
    389      * @param array $options
    390      * @param string $initial
    391      * @param bool $required
    392      * @param array $attrs
    393      * @return void
    394     */
    395     public function multiselect($name, $label, $options, $initial=false, $required=NULL, $attrs=array())
    396     {
    397         $attrs['is_multi'] = true;
    398         $this->select($name, $label, $options, $initial, $required, $attrs);
    399     }
    400 
    401     /**
    402      * @param string $name
    403      * @param string $label
    404      * @param array $options
    405      * @param string $initial
    406      * @param bool $required
    407      * @param array $attrs
    408      * @return void
    409     */
    410     public function radiobuttons($name, $label, $options, $initial=false, $required=NULL, $attrs=array())
    411     {
    412         $params = get_defined_vars();
    413         $params['type'] = __FUNCTION__;
    414         $this->addSingular($name, $params);
    415 
    416         $value = $this->getValue($name);
    417         $this->setValue($name, $value);
    418 
    419         $attrs = $this->filterAttrs($attrs, $name);
    420         $input = '';
    421 
    422         foreach ($options as $key => $text) {
    423 
    424             if ($key == $value && $value !== false && $value !== '' && $value !== NULL) {
    425                 $checked = ' checked="checked"';
    426             } else {
    427                 $checked = '';
    428             }
    429 
    430             $input .= '<label class="{error}">';
    431             $input .= '<input ';
    432             $input .= 'type="radio" ';
    433             $input .= 'name="'.$name.'" ';
    434             $input .= 'id="{input_id}" ';
    435             $input .= 'value="'.self::esc_html($key).'" ';
    436             $input .= $checked;
    437             $input .= '> ';
    438             $input .= $text;
    439             $input .= '</label> ';
    440 
    441         }
    442 
    443         $this->inputs[$name] = $input;
    444 
    445     }
    446 
    447     /**
    448      * @param string $name
    449      * @param string $label
    450      * @param array $options
    451      * @param array $initial
    452      * @param bool $required
    453      * @param array $attrs
    454      * @return void
    455     */
    456     public function checkboxes($name, $label, $options, $initial=array(), $required=NULL, $attrs=array())
    457     {
    458 
    459         $params = get_defined_vars();
    460         $params['type'] = __FUNCTION__;
    461         $this->addMulti($name, $params);
    462 
    463         $value = $this->getValue($name);
    464         $attrs = $this->filterAttrs($attrs, $name);
    465         $input = '';
    466 
    467         foreach ($options as $key => $text) {
    468 
    469             $input_name = $name.'[]';
    470 
    471             if (in_array($key, $value)) {
    472                 $checked = ' checked="checked"';
    473             } else {
    474                 $checked = '';
    475             }
    476 
    477             $input .= '<label class="{error}">';
    478             $input .= '<input ';
    479             $input .= 'type="checkbox" ';
    480             $input .= 'name="'.$input_name.'" ';
    481             $input .= 'id="{input_id}" ';
    482             $input .= 'value="'.self::esc_html($key).'" ';
    483             $input .= $checked;
    484             $input .= '> ';
    485             $input .= $text;
    486             $input .= '</label> ';
    487 
    488         }
    489 
    490         $this->inputs[$name] = $input;
    491 
    492     }
    493 
    494     /**
    495      * @param string $name
    496      * @param string $label
    497      * @param string $initial
    498      * @param array $attrs
    499      * @return void
    500     */
    501     public function checkbox($name, $label, $initial='', $attrs=array())
    502     {
    503 
    504         $params = get_defined_vars();
    505         $params['type'] = __FUNCTION__;
    506         $params['required'] = false;
    507         $this->addInput($name, $params);
    508 
    509         $value = $this->getValue($name);
    510         $value = (bool)$value;
    511         $this->setValue($name, $value);
    512 
    513         if ($value) {
    514             $checked = ' checked="checked"';
    515         } else {
    516             $checked = '';
    517         }
    518 
    519         $input = '<label class="{error}">';
    520         $input .= '<input ';
    521         $input .= 'type="checkbox" ';
    522         $input .= 'name="'.$name.'" ';
    523         $input .= 'id="{input_id}" ';
    524         $input .= 'value="1" ';
    525         $input .= $checked;
    526         $input .= '> ';
    527         $input .= $label;
    528         $input .= '</label> ';
    529 
    530         $this->inputs[$name] = $input;
    531 
    532     }
    533 
    534     /**
    535      * @param string $name
    536      * @param string $label
    537      * @param int|DateTime $initial
    538      * @param bool $required
    539      * @param array $attrs
    540      * @return void
    541     */
    542     public function dateSelect($name, $label, $initial=false, $required=NULL, $attrs=array())
    543     {
    544 
    545         if (is_a($initial, 'DateTime')) {
    546             $initial = $initial->getTimestamp();
    547         }
    548 
    549         $params = get_defined_vars();
    550         $params['type'] = __FUNCTION__;
    551         $this->addField($name, $params);
    552 
    553         if (isset($_REQUEST[$name]) && isset($_REQUEST[$name.'-month']) && isset($_REQUEST[$name.'-year'])) {
    554             $is_valid_date = checkdate($_REQUEST[$name.'-month'], $_REQUEST[$name], $_REQUEST[$name.'-year']);
    555         } else {
    556             $is_valid_date = false;
    557         }
    558 
    559         if (!$this->submitted()) {
    560             $value = $initial;
    561         } elseif ($is_valid_date) {
    562             $value = mktime(0, 0, 0, $_REQUEST[$name.'-month'], $_REQUEST[$name], $_REQUEST[$name.'-year']);
    563         } else {
    564             $value = false;
    565         }
    566 
    567         $this->setValue($name, $value);
    568         $attrs = $this->filterAttrs($attrs, $name);
    569 
    570         if ($this->submitted()) {
    571 
    572             if ($required && !$is_valid_date) {
    573                 $this->error($label.' is not a valid date', $name);
    574             }
    575 
    576             if (empty($attrs['greater_than'])) {
    577                 //do nothing
    578             } elseif ($value < $this->values[$attrs['greater_than']]) {
    579                 $target = $attrs['greater_than'];
    580                 $target_label = $this->fields[$target]['label'];
    581                 $this->error('Date must be after '.$target_label, $name);
    582             }
    583 
    584         }
    585 
    586         $fields = array('d' => 'day', 'm' => 'month', 'Y' => 'year');
    587         $input = '';
    588         $day = array();
    589         $year = array();
    590         $month = array(
    591             1 => 'January',
    592             2 => 'February',
    593             3 => 'March',
    594             4 => 'April',
    595             5 => 'May',
    596             6 => 'June',
    597             7 => 'July',
    598             8 => 'August',
    599             9 => 'September',
    600             10 => 'October',
    601             11 => 'November',
    602             12 => 'December'
    603         );
    604 
    605         if (isset($attrs['year_start'])) {
    606             $year_start = $attrs['year_start'];
    607         } else {
    608             $year_start = date('Y');
    609         }
    610 
    611         if (isset($attrs['year_end'])) {
    612             $year_end = $attrs['year_end'];
    613         } else {
    614             $year_end = $year_start + 5;
    615         }
    616 
    617         for ($i = 1; $i < 32; $i++) {
    618             $day[$i] = $i;
    619         }
    620 
    621         if ($year_start < $year_end) {
    622 
    623             for ($i = $year_start; $i <= $year_end; $i++) {
    624                 $year[$i] = $i;
    625             }
    626 
    627         } else {
    628 
    629             for ($i = $year_start; $i >= $year_end; $i--) {
    630                 $year[$i] = $i;
    631             }
    632 
    633         }
    634 
    635         foreach ($fields as $date_code => $date_input) {
    636 
    637             $input_name = $name.'-'.$date_input;
    638             $input_name = str_replace('-day', '', $input_name);
    639             $input_id = '{input_id}-'.$date_input;
    640 
    641             $input .= '<select ';
    642             $input .= 'name="'.$input_name.'" ';
    643             $input .= 'id="'.$input_id.'" ';
    644             $input .= 'class="{error}" ';
    645             $input .= '>';
    646             $input .= "\n";
    647 
    648             $input .= '<option value="0">['.$date_input.']</option>';
    649             $input .= "\n";
    650 
    651             foreach (${$date_input} as $key => $text) {
    652 
    653                 if (($value && $key == date($date_code, $value))) {
    654                     $selected = ' selected="selected"';
    655                 } else {
    656                     $selected = '';
    657                 }
    658 
    659                 $input .= '<option value="'.$key.'" '.$selected.'>';
    660                 $input .= $text;
    661                 $input .= '</option>';
    662                 $input .= "\n";
    663 
    664             }
    665 
    666             $input .= '</select>';
    667             $input .= "\n";
    668 
    669         }
    670 
    671         $this->inputs[$name] = $input;
    672 
    673     }
    674 
    675     /**
    676      * @param string $name
    677      * @param string $label
    678      * @param int|DateTime $initial
    679      * @param bool $required
    680      * @param array $attrs
    681      * @return void
    682     */
    683     public function datePicker($name, $label, $initial=false, $required=NULL, $attrs=array())
    684     {
    685 
    686         if (is_a($initial, 'DateTime')) {
    687             $initial = $initial->getTimestamp();
    688         }
    689 
    690         $params = get_defined_vars();
    691         $params['type'] = __FUNCTION__;
    692         $this->addField($name, $params);
    693 
    694         if (!$this->submitted()) {
    695             $value = $initial;
    696         } elseif (isset($_REQUEST[$name])) {
    697             $value = strtotime($_REQUEST[$name]);
    698         } else {
    699             $value = 0;
    700         }
    701 
    702         $this->setValue($name, $value);
    703         $attrs = $this->filterAttrs($attrs, $name);
    704 
    705         if ($this->submitted()) {
    706 
    707             if ($required && !$value) {
    708                 $this->error($label.' not provided', $name);
    709             }
    710 
    711             if (empty($attrs['min'])) {
    712                 //do nothing if min not set
    713             } elseif (!$value) {
    714                 //do nothing if value not set
    715             } elseif ($value < $attrs['min']) {
    716                 $this->error($label.' not valid', $name);
    717             }
    718 
    719             if (empty($attrs['max'])) {
    720                 //do nothing if max not set
    721             } elseif (!$value) {
    722                 //do nothing if value not set
    723             } elseif ($attrs['max'] == 'today' && $value > time()) {
    724                 $this->error($label.' not valid', $name);
    725             } elseif ($attrs['max'] != 'today' && $value > $attrs['max']) {
    726                 $this->error($label.' not valid', $name);
    727             }
    728 
    729         }
    730 
    731         if (isset($attrs['format'])) {
    732             $format = $attrs['format'];
    733             $format = str_replace('yyyy', 'Y', $format);
    734             $format = str_replace('yy', 'y', $format);
    735             $format = str_replace('mmmm', 'F', $format);
    736             $format = str_replace('mmm', 'M', $format);
    737             $format = str_replace('mm', '@', $format);
    738             $format = str_replace('m', 'n', $format);
    739             $format = str_replace('@', 'm', $format);
    740             $format = str_replace('dddd', 'l', $format);
    741             $format = str_replace('ddd', 'D', $format);
    742             $format = str_replace('dd', '@', $format);
    743             $format = str_replace('d', 'j', $format);
    744             $format = str_replace('@', 'd', $format);
    745         } else {
    746             $format = 'j F Y';
    747         }
    748 
    749         if ($value) {
    750             $value_display = date($format, $value);
    751         } else {
    752             $value_display = '';
    753         }
    754 
    755         $input = '<input ';
    756         $input .= 'type="text" ';
    757         $input .= 'name="'.$name.'" ';
    758         $input .= 'id="{input_id}" ';
    759         $input .= 'value="'.self::esc_html($value_display).'" ';
    760         $input .= 'class="{error}" ';
    761         $input .= self::make_attr('placeholder', $attrs);
    762         $input .= '>';
    763 
    764         if (isset($attrs['format'])) {
    765             $format = $attrs['format'];
    766         } else {
    767             $format = 'd mmmm yyyy';
    768         }
    769 
    770         if (isset($attrs['num_years'])) {
    771             $num_years = $attrs['num_years'];
    772         } else {
    773             $num_years = 6;
    774         }
    775 
    776         if (isset($attrs['min'])) {
    777             $min = ', min: new Date('.date('Y', $attrs['min']).', '.(date('n', $attrs['min']) - 1).', '.date('j', $attrs['min']).')';
    778         } else {
    779             $min = '';
    780         }
    781 
    782         if (empty($attrs['max'])) {
    783             $max = '';
    784         } elseif ($attrs['max'] == 'today') {
    785             $max = ', max: true';
    786         } else {
    787             $max = ', max: new Date('.date('Y', $attrs['max']).', '.(date('n', $attrs['max']) - 1).', '.date('j', $attrs['max']).')';
    788         }
    789 
    790         //wp_enqueue_style('pickadate', TEMPLATE_URI.'/css/plugins.min.css');
    791         //wp_enqueue_script('pickadate', TEMPLATE_URI.'/js/plugins.min.js', 'jquery');
    792 
    793         ob_start();
    794             ?>
    795             <script>
    796             jQuery('#<?= $this->makeID($name); ?>').pickadate({
    797                 container: 'body',
    798                 selectYears: '<?= $num_years; ?>',
    799                 selectMonths: true,
    800                 format: '<?= $format; ?>',
    801                 formatSubmit: 'yyyy/mm/dd',
    802                 hiddenName: true
    803                 <?= $min; ?>
    804                 <?= $max; ?>
    805             });
    806             </script>
    807             <?
    808         $html = ob_get_contents();
    809         ob_end_clean();
    810 
    811         self::add_to_footer($html);
    812 
    813         $this->inputs[$name] = $input;
    814 
    815     }
    816 
    817     /**
    818      * @param string $name
    819      * @param string $label
    820      * @param string|DateTime $initial
    821      * @param bool $required
    822      * @param array $attrs
    823      * @return void
    824     */
    825     public function timeSelect($name, $label, $initial=false, $required=NULL, $attrs=array())
    826     {
    827 
    828         if (is_a($initial, 'DateTime')) {
    829             $initial = $initial->getTimestamp();
    830         }
    831 
    832         $params = get_defined_vars();
    833         $params['type'] = __FUNCTION__;
    834         $this->addField($name, $params);
    835 
    836         if (!$this->is_submitted && is_numeric($initial)) {
    837             $value = date('H:i', $initial);
    838         } elseif (!$this->submitted()) {
    839             $value = $initial;
    840         } elseif (!isset($_REQUEST[$name.'-hours']) || !isset($_REQUEST[$name.'-mins'])) {
    841             $value = false;
    842         } elseif ($_REQUEST[$name.'-hours'] != '--' && $_REQUEST[$name.'-mins'] != '--') {
    843             $value = $_REQUEST[$name.'-hours'].':'.$_REQUEST[$name.'-mins'];
    844         } else {
    845             $value = false;
    846         }
    847 
    848         $this->setValue($name, $value);
    849 
    850         if ($this->submitted()) {
    851 
    852             if ($required && !$value) {
    853                 $this->error($label.' not provided', $name);
    854             }
    855 
    856         }
    857 
    858         $attrs = $this->filterAttrs($attrs, $name);
    859         $fields = array('hours' => 'hh', 'mins' => 'mm');
    860         $input = '';
    861         $hours = array();
    862         $mins = array();
    863 
    864         if ($value) {
    865             $field_values = array();
    866             $field_values['hours'] = strstr($value, ':', true);
    867             $field_values['mins'] = str_replace(':', '', strstr($value, ':', false));
    868         }
    869 
    870         if (isset($attrs['increments'])) {
    871             $increments = $attrs['increments'];
    872         } else {
    873             $increments = 15;
    874         }
    875 
    876         for ($i = 0; $i <= 23; $i++) {
    877             $j = str_pad($i, 2, '0', STR_PAD_LEFT);
    878             $hours[$j] = $j;
    879         }
    880 
    881         for ($i = 0; $i <= 59; $i = $i + $increments) {
    882             $j = str_pad($i, 2, '0', STR_PAD_LEFT);
    883             $mins[$j] = $j;
    884         }
    885 
    886         foreach ($fields as $time_input => $default) {
    887 
    888             $input_name = $name.'-'.$time_input;
    889             $input_id = '{input_id}-'.$time_input;
    890 
    891             if ($value) {
    892                 $field_value = $field_values[$time_input];
    893             }
    894 
    895             $input .= '<select ';
    896             $input .= 'name="'.$input_name.'" ';
    897             $input .= 'id="'.$input_id.'" ';
    898             $input .= 'class="{error}" ';
    899             $input .= '>';
    900             $input .= "\n";
    901 
    902             if (!$required) {
    903                 $input .= '<option value="--">['.$default.']</option>';
    904                 $input .= "\n";
    905             }
    906 
    907             foreach (${$time_input} as $key => $text) {
    908 
    909                 if ($value && $key == $field_value) {
    910                     $selected = ' selected="selected"';
    911                 } else {
    912                     $selected = '';
    913                 }
    914 
    915                 $input .= '<option value="'.$key.'" '.$selected.'>'.$text.'</option>';
    916                 $input .= "\n";
    917 
    918             }
    919 
    920             $input .= '</select>';
    921             $input .= "\n";
    922 
    923         }
    924 
    925         $this->inputs[$name] = $input;
    926 
    927     }
    928 
    929     /**
    930      * @param string $name
    931      * @param string $label
    932      * @param string $error_msg
    933      * @param bool $initial
    934      * @return void
    935     */
    936     public function confirm($name, $label, $error_msg='You must tick the confirm box', $initial=0)
    937     {
    938 
    939         $options = array(
    940             1 => $label
    941         );
    942 
    943         $this->checkboxes($name, '', $options, array($initial), false, array());
    944 
    945         $value = $this->getValue($name);
    946         $value = reset($value);
    947         $value = intval($value);
    948         $this->setValue($name, $value);
    949 
    950         if ($this->is_submitted && $value != 1) {
    951             $this->error($error_msg, $name);
    952         }
    953 
    954     }
    955 
    956     /**
    957      * @param string $name
    958      * @param string $label
    959      * @param string $initial
    960      * @param bool $required
    961      * @param array $attrs
    962      * @return void
    963     */
    964     public function yesno($name, $label, $initial=false, $required=NULL, $attrs=array())
    965     {
    966         $initial = intval($initial);
    967         $options = array(
    968             1 => 'Yes',
    969             0 => 'No'
    970         );
    971 
    972         $this->radiobuttons($name, $label, $options, $initial, $required, $attrs);
    973     }
    974 
    975     /**
    976      * @param string $name
    977      * @param string $label
    978      * @param string $initial
    979      * @param bool $required
    980      * @param array $attrs
    981      * @return void
    982     */
    983     public function dob($name, $label, $initial=false, $required=NULL, $attrs=array())
    984     {
    985 
    986         $attrs['year_start'] = date('Y');
    987         $attrs['year_end'] = 1920;
    988 
    989         $this->dateSelect($name, $label, $initial, $required, $attrs);
    990 
    991     }
    992 
    993     /**
    994      * @param string $name
    995      * @param string $label
    996      * @param string $initial
    997      * @param bool $required
    998      * @param array $attrs
    999      * @return void
    1000     */
    1001     public function dobPicker($name, $label, $initial=false, $required=NULL, $attrs=array())
    1002     {
    1003         $attrs['min'] = mktime(0, 0, 0, 1, 1, 1920);
    1004         $attrs['max'] = 'today';
    1005         $attrs['num_years'] = 999;
    1006 
    1007         $this->datePicker($name, $label, $initial, $required, $attrs);
    1008     }
    1009 
    1010     /**
    1011      * @param string $name
    1012      * @param string $label
    1013      * @param string $initial
    1014      * @param bool $required
    1015      * @param array $attrs
    1016      * @return void
    1017     */
    1018     public function gender($name, $label, $initial=false, $required=NULL, $attrs=array())
    1019     {
    1020         $options = array(
    1021             'MALE' => 'Male',
    1022             'FEMALE' => 'Female'
    1023         );
    1024 
    1025         if (empty($attrs['use_radio'])) {
    1026             $this->select($name, $label, $options, $initial, $required, $attrs);
    1027         } else {
    1028             $this->radioButtons($name, $label, $options, $initial, $required, $attrs);
    1029         }
    1030     }
    1031 
    1032     /**
    1033      * @param string $name
    1034      * @param string $label
    1035      * @param string $initial
    1036      * @param bool $required
    1037      * @param array $attrs
    1038      * @return void
    1039     */
    1040     public function salutation($name, $label, $initial=false, $required=NULL, $attrs=array())
    1041     {
    1042 
    1043         $options = array(
    1044             'Mr' => 'Mr',
    1045             'Mrs' => 'Mrs',
    1046             'Miss' => 'Miss',
    1047             'Ms' => 'Ms'
    1048         );
    1049 
    1050         $this->select($name, $label, $options, $initial, $required, $attrs);
    1051 
    1052     }
    1053 
    1054     /**
    1055      * @param string $name
    1056      * @param string $label
    1057      * @param string $initial
    1058      * @param bool $required
    1059      * @param array $attrs
    1060      * @return void
    1061     */
    1062     public function email($name, $label, $initial=false, $required=NULL, $attrs=array())
    1063     {
    1064 
    1065         $params = get_defined_vars();
    1066         $params['type'] = __FUNCTION__;
    1067         $this->addInput($name, $params);
    1068 
    1069         $value = $this->getValue($name);
    1070         $value = trim($value);
    1071         $this->setValue($name, $value);
    1072 
    1073         if ($this->submitted()) {
    1074 
    1075             if (!self::validate_email($value)) {
    1076                 $this->error($field['label'].' is not a valid email address', $name, 'IGNORE');
    1077             }
    1078 
    1079         }
    1080 
    1081     }
    1082 
    1083     /**
    1084      * @param string $name
    1085      * @param string $label
    1086      * @param string $label_2
    1087      * @param bool $required
    1088      * @param array $attrs
    1089      * @return void
    1090     */
    1091     public function emailConfirm($name, $label, $label_2, $required=NULL, $attrs=array())
    1092     {
    1093 
    1094         $name_2 = $name.'_confirm';
    1095 
    1096         $this->email($name, $label, '', $required, $attrs);
    1097         $this->email($name_2, $label_2, '', $required, $attrs);
    1098 
    1099         $value_1 = $this->getValue($name);
    1100         $value_2 = $this->getValue($name_2);
    1101 
    1102         if ($this->submitted()) {
    1103 
    1104             if ($value_1 != $value_2) {
    1105                 $this->error('The emails you entered do not match. Please try again', $name_2);
    1106             }
    1107 
    1108         }
    1109 
    1110     }
    1111 
    1112     /**
    1113      * @param string $name
    1114      * @param string $label
    1115      * @param string $initial
    1116      * @param bool $required
    1117      * @param array $attrs
    1118      * @return void
    1119     */
    1120     public function url($name, $label, $initial=false, $required=NULL, $attrs=array())
    1121     {
    1122 
    1123         if (isset($_REQUEST[$name])) {
    1124             $_REQUEST[$name] = trim($_REQUEST[$name]);
    1125         } elseif (!$initial) {
    1126             $initial = 'http://';
    1127         }
    1128 
    1129         $params = get_defined_vars();
    1130         $params['type'] = 'text';
    1131         $this->addInput($name, $params);
    1132 
    1133         $value = $this->getValue($name);
    1134 
    1135         if ($value == 'http://') {
    1136             $value = false;
    1137             $this->setValue($name, $value);
    1138         }
    1139 
    1140         if ($this->submitted()) {
    1141 
    1142             if ($required && !$value) {
    1143                 $this->error($label.' not provided', $name);
    1144             }
    1145 
    1146         }
    1147 
    1148     }
    1149 
    1150     /**
    1151      * @param string $name
    1152      * @param string $label
    1153      * @param string $initial
    1154      * @param bool $required
    1155      * @param array $attrs
    1156      * @return void
    1157     */
    1158     public function number($name, $label, $initial='', $required=NULL, $attrs=array())
    1159     {
    1160 
    1161         $params = get_defined_vars();
    1162         $params['type'] = __FUNCTION__;
    1163         $this->addInput($name, $params);
    1164 
    1165         $value = $this->getValue($name);
    1166 
    1167         if ($this->submitted()) {
    1168 
    1169             if ($required && !intval($value)) {
    1170                 $this->error($label.' cannot be zero', $name);
    1171             }
    1172 
    1173             if ($value && !is_numeric($value)) {
    1174                 $this->error($label.' must be numeric', $name);
    1175             }
    1176 
    1177             if (isset($attrs['min']) && $value < $attrs['min']) {
    1178                 $this->error(sprintf('%s is below the minimum value', $label), $name);
    1179             }
    1180 
    1181             if (isset($attrs['max']) && $value > $attrs['max']) {
    1182                 $this->error(sprintf('%s is above the maximum value', $label), $name);
    1183             }
    1184 
    1185         }
    1186 
    1187     }
    1188 
    1189     /**
    1190      * @param string $name
    1191      * @param string $label
    1192      * @param string $initial
    1193      * @param bool $required
    1194      * @param array $attrs
    1195      * @return void
    1196     */
    1197     public function phone($name, $label, $initial='', $required=NULL, $attrs=array())
    1198     {
    1199 
    1200         $params = get_defined_vars();
    1201         $params['type'] = 'text';
    1202         $this->addInput($name, $params);
    1203 
    1204         $value = $this->getValue($name);
    1205 
    1206         if ($this->submitted()) {
    1207 
    1208             if (strlen($value) > 0 && preg_match('/[A-Za-z]+/', $value)) {
    1209                 $msg = sprintf('%s is not a valid phone number', $value);
    1210                 $this->error($msg, $name, 'IGNORE');
    1211             }
    1212 
    1213         }
    1214 
    1215     }
    1216 
    1217     /**
    1218      * @param string $group_name
    1219      * @param string $label
    1220      * @param array $settings
    1221      * @param array $initial
    1222      * @param bool $required
    1223      * @param array $attrs
    1224      * @return void
    1225     */
    1226     public function settings($group_name, $group_label, $settings, $initial=array(), $required=NULL, $attrs=array())
    1227     {
    1228 
    1229         $initial = (array)$initial;
    1230         $this->checkboxes($group_name, $group_label, $settings, $initial, false, $attrs);
    1231         $value = $this->getValue($group_name);
    1232 
    1233         if ($this->submitted()) {
    1234 
    1235             foreach ($settings as $name => $label) {
    1236 
    1237                 if (in_array($name, $value)) {
    1238                     $this->setValue($name, true);
    1239                 } else {
    1240                     $this->setValue($name, false);
    1241                 }
    1242 
    1243             }
    1244 
    1245             unset($this->values[$group_name]);
    1246 
    1247         }
    1248 
    1249     }
    1250 
    1251     /**
    1252      * @param string $html
    1253      * @return void
    1254      */
    1255     public function html($html)
    1256     {
    1257         end($this->inputs);
    1258         $last_input = key($this->inputs);
    1259 
    1260         if ($last_input) {
    1261             $this->html[$last_input]['after'][] = $html;
    1262         } else {
    1263             $last_input = '__start__';
    1264             $this->html[$last_input]['before'][] = $html;
    1265         }
    1266 
    1267     }
    1268 
    1269     /**
    1270      * @param string $html
    1271      * @return void
    1272      */
    1273     public function prepend($html)
    1274     {
    1275         $this->html['__start__']['before'][] = $html;
    1276     }
    1277 
    1278     /**
    1279      * @param string $input_name
    1280      * @param string $html
    1281      * @return void
    1282      */
    1283     public function before($input_name, $html)
    1284     {
    1285         $this->html[$input_name]['before'][] = $html;
    1286     }
    1287 
    1288     /**
    1289      * @param string $input_name
    1290      * @param string $html
    1291      * @return void
    1292      */
    1293     public function after($input_name, $html)
    1294     {
    1295         $this->html[$input_name]['after'][] = $html;
    1296     }
    1297 
    1298     /**
    1299      * @param string $name
    1300      * @return array
    1301      */
    1302     public function getField($name)
    1303     {
    1304         if (isset($this->fields[$name])) {
    1305             return $this->fields[$name];
    1306         } else {
    1307             return false;
    1308         }
    1309     }
    1310 
    1311     /**
    1312      * @param string $field
    1313      * @return mixed
    1314      */
    1315     public function getValue($field)
    1316     {
    1317         return $this->values[$field];
    1318     }
    1319 
    1320     /**
    1321      * @param string $field
    1322      * @param string $value
    1323      * @return void
    1324      */
    1325     public function setValue($field, $value)
    1326     {
    1327         //TODO$value = Filter::purify($value);
    1328         $this->values[$field] = $value;
    1329     }
    1330 
    1331     /**
    1332      * @return bool
    1333      */
    1334     public function submitted()
    1335     {
    1336         return $this->is_submitted;
    1337     }
    1338 
    1339     /**
    1340      * @return bool
    1341      */
    1342     public function success()
    1343     {
    1344         return $this->has_success;
    1345     }
    1346 
    1347     /**
    1348      * @param string $msg
    1349      * @param string $key
    1350      * @param bool $ignore
    1351      * @return void
    1352      */
    1353     public function error($msg, $key=false, $ignore=false)
    1354     {
    1355 
    1356         $this->has_success = false;
    1357 
    1358         if ($key && !isset($this->errors[$key])) {
    1359             $this->errors[$key] = $msg;
    1360         } elseif (!$ignore) {
    1361             $this->errors[] = $msg;
    1362         }
    1363 
    1364     }
    1365 
    1366     /**
    1367      * @param Exception $Exception
    1368      * @param string $key
    1369      * @param bool $ignore
    1370      * @return void
    1371      */
    1372     public function exception($Exception, $key=false, $ignore=false)
    1373     {
    1374         $msg = $Exception->getMessage();
    1375         $this->error($msg, $key, $ignore);
    1376     }
    1377 
    1378     /**
    1379      * @param string $label
    1380      * @param array $attrs
    1381      * @return void
    1382      */
    1383     public function submit($label, $attrs=array())
    1384     {
    1385         $html = '<div class="'.$this->submit_wrap.'">';
    1386         $html .= '<button type="submit" class="{class}">'.$label.'</button>';
    1387         $html .= '{append}';
    1388         $html .= '</div>';
    1389         $html .= "\n";
    1390 
    1391         if (isset($attrs['append'])) {
    1392             $html = str_replace('{append}', $attrs['append'], $html);
    1393         } else {
    1394             $html = str_replace('{append}', '', $html);
    1395         }
    1396 
    1397         if (isset($attrs['class'])) {
    1398             $html = str_replace('{class}', $attrs['class'], $html);
    1399         } else {
    1400             $html = str_replace('{class}', '', $html);
    1401         }
    1402 
    1403         $this->inputs['submit'] = $html;
    1404     }
    1405 
    1406     /**
    1407      * @return void
    1408      */
    1409     public function display()
    1410     {
    1411 
    1412         echo '<div id="'.$this->form_id.'">';
    1413         echo "\n";
    1414 
    1415         $this->putErrors();
    1416         $this->putForm();
    1417 
    1418         echo '</div>';
    1419         echo "\n";
    1420 
    1421     }
    1422 
    1423     /**
    1424      * @return void
    1425      */
    1426     public function open()
    1427     {
    1428 
    1429         //make action url
    1430         $action = $this->action;
    1431         $action .= ($this->keep_gets ? QSTRING : '');
    1432         $action .= ($this->fragment ? '#'.$this->fragment : '');
    1433 
    1434         //start form
    1435         echo '<form action="'.$action.'" ';
    1436         echo 'method="'.$this->method.'" ';
    1437         echo 'id="'.$this->form_id.'" ';
    1438         echo 'class="'.$this->form_class.'" ';
    1439         echo 'enctype="multipart/form-data">';
    1440         echo "\n";
    1441 
    1442     }
    1443 
    1444     /**
    1445      * @return void
    1446      */
    1447     public function close()
    1448     {
    1449         echo '</form>';
    1450         echo "\n";
    1451     }
    1452 
    1453     /**
    1454      * @return void
    1455      */
    1456     public function putErrors()
    1457     {
    1458 
    1459         if (!$this->errors) {
    1460             return false;
    1461         }
    1462 
    1463         $html = '<div class="'.$this->error_wrap.'">'."\n";
    1464         $html .= '<ul>'."\n";
    1465 
    1466         foreach ($this->errors as $msg) {
    1467             $html .= '<li>'.self::esc_html($msg).'</li>'."\n";
    1468         }
    1469 
    1470         $html .= '</ul>'."\n";
    1471         $html .= '</div>'."\n";
    1472 
    1473         echo $html;
    1474 
    1475     }
    1476 
    1477     /**
    1478      * @return void
    1479      */
    1480     public function putForm()
    1481     {
    1482         //open form
    1483         $this->open();
    1484 
    1485         //put hidden
    1486         $this->putHidden();
    1487 
    1488         //add html
    1489         if (isset($this->html['__start__']['before'])) {
    1490             foreach ($this->html['__start__']['before'] as $html_bit) {
    1491                 echo $html_bit."\n";
    1492             }
    1493         }
    1494 
    1495         //put fields
    1496         foreach ($this->fields as $name => $params) {
    1497             $this->putField($name);
    1498         }
    1499 
    1500         //put submit
    1501         if (isset($this->inputs['submit'])) {
    1502             $this->putField('submit');
    1503         }
    1504 
    1505         //close form
    1506         $this->close();
    1507 
    1508     }
    1509 
    1510     /**
    1511      * @return void
    1512      */
    1513     public function putHidden()
    1514     {
    1515 
    1516         $html = '<div style="display:none">'."\n";
    1517 
    1518         //for forms with get method, add relevant hidden fields to match current query string
    1519         if ($this->keep_gets && $this->method == 'get') {
    1520 
    1521             $qstring = trim(QSTRING, '?');
    1522             $vars = explode('&', $qstring);
    1523             $vars = array_filter($vars);
    1524 
    1525             foreach ($vars as $var) {
    1526 
    1527                 $var = explode('=', $var);
    1528                 $key = urldecode($var[0]);
    1529                 $val = urldecode($var[1]);
    1530                 $master_key = strstr($key, '[', true);
    1531 
    1532                 if (!$master_key) {
    1533                     $master_key = $key;
    1534                 }
    1535 
    1536                 if (isset($this->fields[$master_key]) || isset($this->hidden[$master_key])) {
    1537                     continue; //skip fields that exist in this form
    1538                 }
    1539 
    1540                 $html .= '<input type="hidden" name="'.$key.'" value="'.$val.'">'."\n";
    1541 
    1542             }
    1543 
    1544         }
    1545 
    1546         foreach ($this->hidden as $name => $value) {
    1547             $html .= '<input type="hidden" name="'.$name.'" value="'.$value.'">'."\n";
    1548         }
    1549 
    1550         $html .= '</div>'."\n";
    1551 
    1552         echo $html;
    1553 
    1554     }
    1555 
    1556     /**
    1557      * @param string $name
    1558      * @return void
    1559      */
    1560     public function putField($name)
    1561     {
    1562         $html = '';
    1563 
    1564         if (isset($this->html[$name]['before'])) {
    1565             foreach ($this->html[$name]['before'] as $html_bit) {
    1566                 $html .= $html_bit."\n";
    1567             }
    1568         }
    1569 
    1570         if ($name == 'submit') {
    1571             $html .= $this->inputs[$name];
    1572         } elseif (empty($this->fields[$name])) {
    1573             return;
    1574         } else {
    1575 
    1576             if (empty($this->fields[$name]['attrs']['lang'])) {
    1577                 $data_lang = '';
    1578             } else {
    1579                 $data_lang = 'data-lang="'.$this->fields[$name]['attrs']['lang'].'"';
    1580             }
    1581 
    1582             $label_html = $this->putLabel($name, false);
    1583             $input_html = $this->putInput($name, false);
    1584             $helper_html = $this->putHelper($name, false);
    1585             $type = $this->fields[$name]['type'];
    1586             $type_modifier = '__'.strtolower($type);
    1587 
    1588             $html .= '<div class="'.$this->field_wrap.' '.$type_modifier.'" '.$data_lang.'>'."\n";
    1589             $html .= '{label}';
    1590             $html .= '<div class="'.$this->input_wrap.'">';
    1591             $html .= '{input}';
    1592             $html .= '</div>';
    1593             $html .= '{helper}'."\n";
    1594             $html .= '</div>'."\n";
    1595 
    1596             $html = str_replace('{label}', $label_html, $html);
    1597             $html = str_replace('{input}', $input_html, $html);
    1598             $html = str_replace('{helper}', $helper_html, $html);
    1599         }
    1600 
    1601         if (isset($this->html[$name]['after'])) {
    1602             foreach ($this->html[$name]['after'] as $html_bit) {
    1603                 $html .= $html_bit."\n";
    1604             }
    1605         }
    1606 
    1607         echo $html;
    1608 
    1609     }
    1610 
    1611     /**
    1612      * @param string $name
    1613      * @param bool $echo
    1614      * @return string
    1615      */
    1616     public function putLabel($name, $echo=true)
    1617     {
    1618 
    1619         //make id
    1620         $input_id = $this->makeID($name);
    1621 
    1622         //error class
    1623         if (isset($this->errors[$name])) {
    1624             $error_class = $this->error_class;
    1625         } else {
    1626             $error_class = '';
    1627         }
    1628 
    1629         //required html
    1630         if (empty($this->fields[$name]['required'])) {
    1631             $required_html = '';
    1632         } else {
    1633             $required_html = ' <span class="'.$this->required_wrap.'">*</span>';
    1634         }
    1635 
    1636         //label text
    1637         if (isset($this->labels[$name])) {
    1638             $label_text = $this->labels[$name];
    1639         } else {
    1640             $label_text = $this->fields[$name]['label'];
    1641         }
    1642 
    1643         //sublabel
    1644         if (isset($this->fields[$name]['attrs']['sublabel'])) {
    1645             $sublabel = $this->fields[$name]['attrs']['sublabel'];
    1646         } elseif (isset($this->sublabels[$name])) {
    1647             $sublabel = $this->sublabels[$name];
    1648         } else {
    1649             $sublabel = false;
    1650         }
    1651 
    1652         if ($sublabel) {
    1653             $sublabel_html = '<span class="'.$this->sublabel_wrap.'">';
    1654             $sublabel_html .= $sublabel;
    1655             $sublabel_html .= '</span>';
    1656         } else {
    1657             $sublabel_html = '';
    1658         }
    1659 
    1660         //label
    1661         $html = '<div class="'.$this->label_wrap.'">';
    1662         $html .= '<label for="{input_id}" class="{error}">';
    1663         $html .= '{label_text}';
    1664         $html .= '{label_required}';
    1665         $html .= '</label>';
    1666         $html .= '{sublabel}';
    1667         $html .= '</div>';
    1668         $html .= "\n";
    1669 
    1670         $html = str_replace('{input_id}', $input_id, $html);
    1671         $html = str_replace('for=""', '', $html); //remove blank for=""
    1672         $html = str_replace('{error}', $error_class, $html);
    1673         $html = str_replace('{label_text}', $label_text, $html);
    1674         $html = str_replace('{label_required}', $required_html, $html);
    1675         $html = str_replace('{sublabel}', $sublabel_html, $html);
    1676 
    1677         if ($echo) {
    1678             echo $html;
    1679         } else {
    1680             return $html;
    1681         }
    1682 
    1683     }
    1684 
    1685     /**
    1686      * @param string $name
    1687      * @param bool $echo
    1688      * @return string
    1689      */
    1690     public function putInput($name, $echo=true)
    1691     {
    1692 
    1693         //make id
    1694         $input_id = $this->makeID($name);
    1695 
    1696         //error class
    1697         if (isset($this->errors[$name])) {
    1698             $error_class = $this->error_class;
    1699         } else {
    1700             $error_class = '';
    1701         }
    1702 
    1703         $html = $this->inputs[$name];
    1704         $html = str_replace('{input_id}', $input_id, $html);
    1705         $html = str_replace('{error}', $error_class, $html);
    1706 
    1707         if ($echo) {
    1708             echo $html;
    1709         } else {
    1710             return $html;
    1711         }
    1712 
    1713     }
    1714 
    1715     /**
    1716      * @param string $name
    1717      * @param bool $echo
    1718      * @return string
    1719      */
    1720     public function putHelper($name, $echo=true)
    1721     {
    1722 
    1723         if (isset($this->fields[$name]['attrs']['helper'])) {
    1724             $helper_text = $this->fields[$name]['attrs']['helper'];
    1725         } elseif (isset($this->helpers[$name])) {
    1726             $helper_text = $this->helpers[$name];
    1727         } else {
    1728             $helper_text = false;
    1729         }
    1730 
    1731         if ($helper_text) {
    1732 
    1733             $html = '<div class="'.$this->helper_wrap.'">';
    1734             $html .= '<i class="'.$this->helper_wrap.'-icon">i</i>';
    1735             $html .= '<span class="'.$this->helper_wrap.'-text">';
    1736             $html .= '{helper_text}';
    1737             $html .= '</span>';
    1738             $html .= '</div>';
    1739 
    1740             $html = str_replace("{helper_text}", $helper_text, $html);
    1741 
    1742         } else {
    1743             $html = '';
    1744         }
    1745 
    1746         if ($echo) {
    1747             echo $html;
    1748         } else {
    1749             return $html;
    1750         }
    1751 
    1752     }
    1753 
    1754     /**
    1755      * @param string $name
    1756      * @return string
    1757      */
    1758     protected function makeID($name)
    1759     {
    1760         return $this->form_id.'-'.$name;
    1761     }
    1762 
    1763     /**
    1764      * @param array $attrs
    1765      * @param string $name
    1766      * @return array
    1767      */
    1768     protected function filterAttrs($attrs, $name)
    1769     {
    1770         if (isset($this->fields[$name]['label'])) {
    1771             $label = $this->fields[$name]['label'];
    1772         } else {
    1773             $label = '';
    1774         }
    1775 
    1776         if (isset($attrs['placeholder'])) {
    1777 
    1778             if ($attrs['placeholder'] === true) {
    1779                 $attrs['placeholder'] = $label;
    1780             } else {
    1781                 //do nothing if manual placeholder
    1782             }
    1783 
    1784         } elseif (isset($this->placeholders[$name])) {
    1785             $attrs['placeholder'] = $this->placeholders[$name];
    1786         } elseif ($this->placeholder_all) {
    1787             $attrs['placeholder'] = $label;
    1788         }
    1789 
    1790         return $attrs;
    1791     }
    1792 
    1793     /**
    1794      * @param string $name
    1795      * @return bool
    1796      */
    1797     public function isRequired($name)
    1798     {
    1799         $field = $this->getField($name);
    1800 
    1801         if (!$field) {
    1802             return;
    1803         } elseif ($field['required'] === NULL) {
    1804             return $this->require_all;
    1805         } else {
    1806             return $field['required'];
    1807         }
    1808     }
    1809 
    1810     /**
    1811      * @param string $key
    1812      * @param array $attrs
    1813      * @param mixed $default
    1814      * @return mixed
    1815      */
    1816     protected static function make_attr($key, $attrs, $default=false)
    1817     {
    1818 
    1819         if (isset($attrs[$key])) {
    1820             return ' '.$key.'="'.$attrs[$key].'"';
    1821         } else if ($default) {
    1822             return ' '.$key.'="'.$default.'"';
    1823         } else {
    1824             return '';
    1825         }
    1826 
    1827     }
    1828 
    1829     /**
    1830      * @param string $string
    1831      * @return string
    1832      */
    1833     protected static function esc_html($string)
    1834     {
    1835         return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
    1836     }
    1837 
    1838     /**
    1839      * @todo Validate the email passed.
    1840      * @return bool
    1841      */
    1842     public static function validate_email($email)
    1843     {
    1844         return true;
    1845     }
    1846 
    1847     /**
    1848      * @param string $html
    1849      * @return bool
    1850      */
    1851     public static function add_to_footer($html)
    1852     {
    1853 
    1854         add_action('wp_footer', function() use ($html){
    1855             echo $html;
    1856         }, 100);
    1857 
    1858     }
     6    protected $uniquevar;
     7    protected $is_submitted;
     8    protected $has_success;
     9    protected $values = array();
     10    protected $fields = array();
     11    protected $hidden = array();
     12    protected $errors = array();
     13    protected $inputs = array();
     14    protected $html = array();
     15
     16    public $require_all = true;
     17    public $action;
     18    public $method = 'post';
     19    public $form_id;
     20    public $form_class;
     21    public $error_class = 'error';
     22    public $error_wrap = 'error_feedback';
     23    public $field_wrap = 'field_wrap';
     24    public $label_wrap = 'label_wrap';
     25    public $input_wrap = 'input_wrap';
     26    public $submit_wrap = 'submit_wrap';
     27    public $required_wrap = 'required';
     28    public $sublabel_wrap = 'sublabel_wrap';
     29    public $helper_wrap = 'helper_wrap';
     30    public $keep_gets = true;
     31    public $placeholder_all = false;
     32    public $placeholders = array();
     33    public $labels = array();
     34    public $sublabels = array();
     35    public $helpers = array();
     36    public $fragment;
     37
     38    /**
     39     * @return mixed
     40     */
     41    public function __get($name)
     42    {
     43        return $this->{$name};
     44    }
     45
     46    /**
     47     * @param string $uniquevar
     48     * @return void
     49     */
     50    public function __construct($uniquevar='posted')
     51    {
     52
     53        $this->action = URI;
     54        $this->uniquevar = $uniquevar;
     55        $this->form_id = $uniquevar;
     56        $this->hidden($this->uniquevar, 1);
     57
     58        unset($this->values[$this->uniquevar]);
     59
     60        if (isset($_REQUEST[$this->uniquevar]) && $_REQUEST[$this->uniquevar] == 1) {
     61            $this->is_submitted = true;
     62            $this->has_success = true; //this gets set false if we hit an error
     63        }
     64
     65    }
     66
     67    /**
     68     * @param array $params
     69     * @return void
     70     */
     71    public function addField($name, $params)
     72    {
     73        $defaults = array(
     74            'type' => '',
     75            'label' => '',
     76            'options' => array(),
     77            'initial' => '',
     78            'required' => NULL,
     79            'attrs' => array()
     80        );
     81
     82        $params = array_merge($defaults, $params);
     83
     84        if (isset($params['name'])) {
     85            unset($params['name']);
     86        }
     87
     88        $this->fields[$name] = $params;
     89    }
     90
     91    /**
     92     * @param string $name
     93     * @param array $params
     94     * @return void
     95     */
     96    protected function addInput($name, $params)
     97    {
     98        $initial = $params['initial'];
     99
     100        if (!$this->submitted()) {
     101            $value = $initial;
     102        } elseif (isset($_REQUEST[$name])) {
     103            $value = $_REQUEST[$name];
     104        } else {
     105            $value = '';
     106        }
     107
     108        $this->addField($name, $params);
     109        $this->setValue($name, $value);
     110
     111        $type = $params['type'];
     112        $label = $params['label'];
     113        $required = $this->isRequired($name);
     114        $attrs = $params['attrs'];
     115        $attrs = $this->filterAttrs($attrs, $name);
     116
     117        if ($this->submitted()) {
     118
     119            if ($required && $value == '') {
     120                $this->error($label.' not provided', $name);
     121            } elseif ($type == 'text' && isset($attrs['limit']) && strlen($value) > $attrs['limit']) {
     122                $this->error('Cannot enter more than '.$attrs['limit'].' characters', $name);
     123            }
     124
     125        }
     126
     127        $input = '<input ';
     128        $input .= 'type="'.$type.'" ';
     129        $input .= 'name="'.$name.'" ';
     130        $input .= 'id="{input_id}" ';
     131        $input .= 'value="'.self::esc_html($value).'" ';
     132        $input .= 'class="{error}" ';
     133        $input .= self::make_attr('placeholder', $attrs);
     134        $input .= self::make_attr('readonly', $attrs);
     135        $input .= self::make_attr('disabled', $attrs);
     136        $input .= self::make_attr('autocomplete', $attrs);
     137        $input .= self::make_attr('step', $attrs);
     138        $input .= self::make_attr('min', $attrs);
     139        $input .= self::make_attr('max', $attrs);
     140        $input .= '>';
     141
     142        $this->inputs[$name] = $input;
     143
     144    }
     145
     146    /**
     147     * @param string $name
     148     * @param array $params
     149     * @return void
     150     */
     151    protected function addSingular($name, $params)
     152    {
     153        $initial = $params['initial'];
     154        $label = $params['label'];
     155
     156        if (!$this->submitted()) {
     157            $value = $initial;
     158        } else if (isset($_REQUEST[$name])) {
     159            $value = $_REQUEST[$name];
     160        } else {
     161            $value = '';
     162        }
     163
     164        if (!$value) {
     165            $value = ''; //convert all types of false to string
     166        }
     167
     168        $this->addField($name, $params);
     169        $this->setValue($name, $value);
     170
     171        $required = $this->isRequired($name);
     172
     173        if ($this->submitted()) {
     174
     175            if ($required && !$value) {
     176                $this->error($label.' not provided', $name);
     177            }
     178
     179        }
     180
     181    }
     182
     183    /**
     184     * @param string $name
     185     * @param array $params
     186     * @return void
     187     */
     188    protected function addMulti($name, $params)
     189    {
     190        $initial = $params['initial'];
     191        $label = $params['label'];
     192
     193        if (!$this->submitted()) {
     194            $value = (array)$initial;
     195        } elseif (isset($_REQUEST[$name])) {
     196            $value = $_REQUEST[$name];
     197        } else {
     198            $value = array();
     199        }
     200
     201        $this->addField($name, $params);
     202        $this->setValue($name, $value);
     203
     204        $required = $this->isRequired($name);
     205
     206        if ($this->submitted()) {
     207
     208            if ($required && count($this->values[$name]) < 1) {
     209                $this->error($label.' not provided', $name);
     210            }
     211
     212        }
     213
     214    }
     215
     216    /**
     217    * @param string $name
     218    * @param string $value
     219    * @return void
     220    */
     221    public function hidden($name, $value)
     222    {
     223
     224        if ($this->is_submitted && isset($_REQUEST[$name])) {
     225            $value = $_REQUEST[$name];
     226        }
     227
     228        $this->hidden[$name] = $value;
     229        $this->values[$name] = $value;
     230
     231    }
     232
     233    /**
     234     * @param string $name
     235     * @param string $label
     236     * @param string $initial
     237     * @param bool $required
     238     * @param array $attrs
     239     * @return void
     240    */
     241    public function text($name, $label, $initial='', $required=NULL, $attrs=array())
     242    {
     243        $params = get_defined_vars();
     244        $params['type'] = __FUNCTION__;
     245        $this->addInput($name, $params);
     246    }
     247
     248    /**
     249     * @param string $name
     250     * @param string $label
     251     * @param string $initial
     252     * @param bool $required
     253     * @param array $attrs
     254     * @return void
     255    */
     256    public function textarea($name, $label, $initial='', $required=NULL, $attrs=array())
     257    {
     258
     259        $params = get_defined_vars();
     260        $params['type'] = __FUNCTION__;
     261        $this->addInput($name, $params);
     262
     263        $attrs = $this->filterAttrs($attrs, $name);
     264        $value = $this->getValue($name);
     265
     266        $input = '<textarea ';
     267        $input .= 'name="'.$name.'" ';
     268        $input .= 'id="{input_id}" ';
     269        $input .= 'class="{error}" ';
     270        $input .= self::make_attr('placeholder', $attrs);
     271        $input .= self::make_attr('readonly', $attrs);
     272        $input .= self::make_attr('disabled', $attrs);
     273        $input .= self::make_attr('rows', $attrs);
     274        $input .= self::make_attr('cols', $attrs);
     275        $input .= '>';
     276        $input .= self::esc_html($value);
     277        $input .= '</textarea>';
     278
     279        $this->inputs[$name] = $input;
     280
     281    }
     282
     283    /**
     284     * @param string $name
     285     * @param string $label
     286     * @param array $options
     287     * @param string $initial
     288     * @param bool $required
     289     * @param array $attrs
     290     * @return void
     291    */
     292    public function select($name, $label, $options, $initial=false, $required=NULL, $attrs=array())
     293    {
     294        $params = get_defined_vars();
     295        $params['type'] = __FUNCTION__;
     296        $attrs = $this->filterAttrs($attrs, $name);
     297
     298        if (empty($attrs['is_multi'])) {
     299            $this->addSingular($name, $params);
     300            $is_multi = false;
     301            $multiple = '';
     302            $input_name = $name;
     303        } else {
     304            $this->addMulti($name, $params);
     305            $is_multi = true;
     306            $multiple = ' multiple="multiple"';
     307            $input_name = $name.'[]';
     308        }
     309
     310        $value = $this->getValue($name);
     311
     312        $input = '<select name="'.$input_name.'" ';
     313        $input .= 'id="{input_id}" ';
     314        $input .= 'class="{error}" ';
     315        $input .= $multiple;
     316        $input .= '>';
     317        $input .= "\n";
     318
     319        if (!isset($attrs['first_option'])) {
     320            $input .= '<option value="0">[please select]</option>';
     321            $input .= "\n";
     322        } elseif ($attrs['first_option']) {
     323            $input .= '<option value="0">'.$attrs['first_option'].'</option>';
     324            $input .= "\n";
     325        }
     326
     327        foreach ($options as $key => $text) {
     328
     329            if (is_array($text)) { //optgroups
     330
     331                $input .= '<optgroup label="'.$key.'">'."\n";
     332
     333                foreach ($text as $key => $text) {
     334
     335                    if ($is_multi && in_array($key, $value)) {
     336                        $selected = ' selected="selected"';
     337                    } elseif ($key == $value) {
     338                        $selected = ' selected="selected"';
     339                    } else {
     340                        $selected = '';
     341                    }
     342
     343                    if (isset($attrs['disabled']) && in_array($key, $attrs['disabled'])) {
     344                        $disabled = ' disabled="disabled"';
     345                    } else {
     346                        $disabled = '';
     347                    }
     348
     349                    $input .= '<option value="'.$key.'" '.$selected.$disabled.'>'.$text.'</option>';
     350                    $input .= "\n";
     351
     352                }
     353
     354                $input .= '</optgroup>';
     355                $input .= "\n";
     356
     357            } else {
     358
     359                if ($is_multi && in_array($key, $value)) {
     360                    $selected = ' selected="selected"';
     361                } elseif ($key == $value) {
     362                    $selected = ' selected="selected"';
     363                } else {
     364                    $selected = '';
     365                }
     366
     367                if (isset($attrs['disabled']) && in_array($key, $attrs['disabled'])) {
     368                    $disabled = ' disabled="disabled"';
     369                } else {
     370                    $disabled = '';
     371                }
     372
     373                $input .= '<option value="'.$key.'" '.$selected.$disabled.'>'.$text.'</option>';
     374                $input .= "\n";
     375
     376            }
     377
     378        }
     379
     380        $input .= '</select>';
     381
     382        $this->inputs[$name] = $input;
     383
     384    }
     385
     386    /**
     387     * @param string $name
     388     * @param string $label
     389     * @param array $options
     390     * @param string $initial
     391     * @param bool $required
     392     * @param array $attrs
     393     * @return void
     394    */
     395    public function multiselect($name, $label, $options, $initial=false, $required=NULL, $attrs=array())
     396    {
     397        $attrs['is_multi'] = true;
     398        $this->select($name, $label, $options, $initial, $required, $attrs);
     399    }
     400
     401    /**
     402     * @param string $name
     403     * @param string $label
     404     * @param array $options
     405     * @param string $initial
     406     * @param bool $required
     407     * @param array $attrs
     408     * @return void
     409    */
     410    public function radiobuttons($name, $label, $options, $initial=false, $required=NULL, $attrs=array())
     411    {
     412        $params = get_defined_vars();
     413        $params['type'] = __FUNCTION__;
     414        $this->addSingular($name, $params);
     415
     416        $value = $this->getValue($name);
     417        $this->setValue($name, $value);
     418
     419        $attrs = $this->filterAttrs($attrs, $name);
     420        $input = '';
     421
     422        foreach ($options as $key => $text) {
     423
     424            if ($key == $value && $value !== false && $value !== '' && $value !== NULL) {
     425                $checked = ' checked="checked"';
     426            } else {
     427                $checked = '';
     428            }
     429
     430            $input .= '<label class="{error}">';
     431            $input .= '<input ';
     432            $input .= 'type="radio" ';
     433            $input .= 'name="'.$name.'" ';
     434            $input .= 'id="{input_id}" ';
     435            $input .= 'value="'.self::esc_html($key).'" ';
     436            $input .= $checked;
     437            $input .= '> ';
     438            $input .= $text;
     439            $input .= '</label> ';
     440
     441        }
     442
     443        $this->inputs[$name] = $input;
     444
     445    }
     446
     447    /**
     448     * @param string $name
     449     * @param string $label
     450     * @param array $options
     451     * @param array $initial
     452     * @param bool $required
     453     * @param array $attrs
     454     * @return void
     455    */
     456    public function checkboxes($name, $label, $options, $initial=array(), $required=NULL, $attrs=array())
     457    {
     458
     459        $params = get_defined_vars();
     460        $params['type'] = __FUNCTION__;
     461        $this->addMulti($name, $params);
     462
     463        $value = $this->getValue($name);
     464        $attrs = $this->filterAttrs($attrs, $name);
     465        $input = '';
     466
     467        foreach ($options as $key => $text) {
     468
     469            $input_name = $name.'[]';
     470
     471            if (in_array($key, $value)) {
     472                $checked = ' checked="checked"';
     473            } else {
     474                $checked = '';
     475            }
     476
     477            $input .= '<label class="{error}">';
     478            $input .= '<input ';
     479            $input .= 'type="checkbox" ';
     480            $input .= 'name="'.$input_name.'" ';
     481            $input .= 'id="{input_id}" ';
     482            $input .= 'value="'.self::esc_html($key).'" ';
     483            $input .= $checked;
     484            $input .= '> ';
     485            $input .= $text;
     486            $input .= '</label> ';
     487
     488        }
     489
     490        $this->inputs[$name] = $input;
     491
     492    }
     493
     494    /**
     495     * @param string $name
     496     * @param string $label
     497     * @param string $initial
     498     * @param array $attrs
     499     * @return void
     500    */
     501    public function checkbox($name, $label, $initial='', $attrs=array())
     502    {
     503
     504        $params = get_defined_vars();
     505        $params['type'] = __FUNCTION__;
     506        $params['required'] = false;
     507        $this->addInput($name, $params);
     508
     509        $value = $this->getValue($name);
     510        $value = (bool)$value;
     511        $this->setValue($name, $value);
     512
     513        if ($value) {
     514            $checked = ' checked="checked"';
     515        } else {
     516            $checked = '';
     517        }
     518
     519        $input = '<label class="{error}">';
     520        $input .= '<input ';
     521        $input .= 'type="checkbox" ';
     522        $input .= 'name="'.$name.'" ';
     523        $input .= 'id="{input_id}" ';
     524        $input .= 'value="1" ';
     525        $input .= $checked;
     526        $input .= '> ';
     527        $input .= $label;
     528        $input .= '</label> ';
     529
     530        $this->inputs[$name] = $input;
     531
     532    }
     533
     534    /**
     535     * @param string $name
     536     * @param string $label
     537     * @param int|DateTime $initial
     538     * @param bool $required
     539     * @param array $attrs
     540     * @return void
     541    */
     542    public function dateSelect($name, $label, $initial=false, $required=NULL, $attrs=array())
     543    {
     544
     545        if (is_a($initial, 'DateTime')) {
     546            $initial = $initial->getTimestamp();
     547        }
     548
     549        $params = get_defined_vars();
     550        $params['type'] = __FUNCTION__;
     551        $this->addField($name, $params);
     552
     553        if (isset($_REQUEST[$name]) && isset($_REQUEST[$name.'-month']) && isset($_REQUEST[$name.'-year'])) {
     554            $is_valid_date = checkdate($_REQUEST[$name.'-month'], $_REQUEST[$name], $_REQUEST[$name.'-year']);
     555        } else {
     556            $is_valid_date = false;
     557        }
     558
     559        if (!$this->submitted()) {
     560            $value = $initial;
     561        } elseif ($is_valid_date) {
     562            $value = mktime(0, 0, 0, $_REQUEST[$name.'-month'], $_REQUEST[$name], $_REQUEST[$name.'-year']);
     563        } else {
     564            $value = false;
     565        }
     566
     567        $this->setValue($name, $value);
     568        $attrs = $this->filterAttrs($attrs, $name);
     569
     570        if ($this->submitted()) {
     571
     572            if ($required && !$is_valid_date) {
     573                $this->error($label.' is not a valid date', $name);
     574            }
     575
     576            if (empty($attrs['greater_than'])) {
     577                //do nothing
     578            } elseif ($value < $this->values[$attrs['greater_than']]) {
     579                $target = $attrs['greater_than'];
     580                $target_label = $this->fields[$target]['label'];
     581                $this->error('Date must be after '.$target_label, $name);
     582            }
     583
     584        }
     585
     586        $fields = array('d' => 'day', 'm' => 'month', 'Y' => 'year');
     587        $input = '';
     588        $day = array();
     589        $year = array();
     590        $month = array(
     591            1 => 'January',
     592            2 => 'February',
     593            3 => 'March',
     594            4 => 'April',
     595            5 => 'May',
     596            6 => 'June',
     597            7 => 'July',
     598            8 => 'August',
     599            9 => 'September',
     600            10 => 'October',
     601            11 => 'November',
     602            12 => 'December'
     603        );
     604
     605        if (isset($attrs['year_start'])) {
     606            $year_start = $attrs['year_start'];
     607        } else {
     608            $year_start = date('Y');
     609        }
     610
     611        if (isset($attrs['year_end'])) {
     612            $year_end = $attrs['year_end'];
     613        } else {
     614            $year_end = $year_start + 5;
     615        }
     616
     617        for ($i = 1; $i < 32; $i++) {
     618            $day[$i] = $i;
     619        }
     620
     621        if ($year_start < $year_end) {
     622
     623            for ($i = $year_start; $i <= $year_end; $i++) {
     624                $year[$i] = $i;
     625            }
     626
     627        } else {
     628
     629            for ($i = $year_start; $i >= $year_end; $i--) {
     630                $year[$i] = $i;
     631            }
     632
     633        }
     634
     635        foreach ($fields as $date_code => $date_input) {
     636
     637            $input_name = $name.'-'.$date_input;
     638            $input_name = str_replace('-day', '', $input_name);
     639            $input_id = '{input_id}-'.$date_input;
     640
     641            $input .= '<select ';
     642            $input .= 'name="'.$input_name.'" ';
     643            $input .= 'id="'.$input_id.'" ';
     644            $input .= 'class="{error}" ';
     645            $input .= '>';
     646            $input .= "\n";
     647
     648            $input .= '<option value="0">['.$date_input.']</option>';
     649            $input .= "\n";
     650
     651            foreach (${$date_input} as $key => $text) {
     652
     653                if (($value && $key == date($date_code, $value))) {
     654                    $selected = ' selected="selected"';
     655                } else {
     656                    $selected = '';
     657                }
     658
     659                $input .= '<option value="'.$key.'" '.$selected.'>';
     660                $input .= $text;
     661                $input .= '</option>';
     662                $input .= "\n";
     663
     664            }
     665
     666            $input .= '</select>';
     667            $input .= "\n";
     668
     669        }
     670
     671        $this->inputs[$name] = $input;
     672
     673    }
     674
     675    /**
     676     * @param string $name
     677     * @param string $label
     678     * @param int|DateTime $initial
     679     * @param bool $required
     680     * @param array $attrs
     681     * @return void
     682    */
     683    public function datePicker($name, $label, $initial=false, $required=NULL, $attrs=array())
     684    {
     685
     686        if (is_a($initial, 'DateTime')) {
     687            $initial = $initial->getTimestamp();
     688        }
     689
     690        $params = get_defined_vars();
     691        $params['type'] = __FUNCTION__;
     692        $this->addField($name, $params);
     693
     694        if (!$this->submitted()) {
     695            $value = $initial;
     696        } elseif (isset($_REQUEST[$name])) {
     697            $value = strtotime($_REQUEST[$name]);
     698        } else {
     699            $value = 0;
     700        }
     701
     702        $this->setValue($name, $value);
     703        $attrs = $this->filterAttrs($attrs, $name);
     704
     705        if ($this->submitted()) {
     706
     707            if ($required && !$value) {
     708                $this->error($label.' not provided', $name);
     709            }
     710
     711            if (empty($attrs['min'])) {
     712                //do nothing if min not set
     713            } elseif (!$value) {
     714                //do nothing if value not set
     715            } elseif ($value < $attrs['min']) {
     716                $this->error($label.' not valid', $name);
     717            }
     718
     719            if (empty($attrs['max'])) {
     720                //do nothing if max not set
     721            } elseif (!$value) {
     722                //do nothing if value not set
     723            } elseif ($attrs['max'] == 'today' && $value > time()) {
     724                $this->error($label.' not valid', $name);
     725            } elseif ($attrs['max'] != 'today' && $value > $attrs['max']) {
     726                $this->error($label.' not valid', $name);
     727            }
     728
     729        }
     730
     731        if (isset($attrs['format'])) {
     732            $format = $attrs['format'];
     733            $format = str_replace('yyyy', 'Y', $format);
     734            $format = str_replace('yy', 'y', $format);
     735            $format = str_replace('mmmm', 'F', $format);
     736            $format = str_replace('mmm', 'M', $format);
     737            $format = str_replace('mm', '@', $format);
     738            $format = str_replace('m', 'n', $format);
     739            $format = str_replace('@', 'm', $format);
     740            $format = str_replace('dddd', 'l', $format);
     741            $format = str_replace('ddd', 'D', $format);
     742            $format = str_replace('dd', '@', $format);
     743            $format = str_replace('d', 'j', $format);
     744            $format = str_replace('@', 'd', $format);
     745        } else {
     746            $format = 'j F Y';
     747        }
     748
     749        if ($value) {
     750            $value_display = date($format, $value);
     751        } else {
     752            $value_display = '';
     753        }
     754
     755        $input = '<input ';
     756        $input .= 'type="text" ';
     757        $input .= 'name="'.$name.'" ';
     758        $input .= 'id="{input_id}" ';
     759        $input .= 'value="'.self::esc_html($value_display).'" ';
     760        $input .= 'class="{error}" ';
     761        $input .= self::make_attr('placeholder', $attrs);
     762        $input .= '>';
     763
     764        if (isset($attrs['format'])) {
     765            $format = $attrs['format'];
     766        } else {
     767            $format = 'd mmmm yyyy';
     768        }
     769
     770        if (isset($attrs['num_years'])) {
     771            $num_years = $attrs['num_years'];
     772        } else {
     773            $num_years = 6;
     774        }
     775
     776        if (isset($attrs['min'])) {
     777            $min = ', min: new Date('.date('Y', $attrs['min']).', '.(date('n', $attrs['min']) - 1).', '.date('j', $attrs['min']).')';
     778        } else {
     779            $min = '';
     780        }
     781
     782        if (empty($attrs['max'])) {
     783            $max = '';
     784        } elseif ($attrs['max'] == 'today') {
     785            $max = ', max: true';
     786        } else {
     787            $max = ', max: new Date('.date('Y', $attrs['max']).', '.(date('n', $attrs['max']) - 1).', '.date('j', $attrs['max']).')';
     788        }
     789
     790        //wp_enqueue_style('pickadate', TEMPLATE_URI.'/css/plugins.min.css');
     791        //wp_enqueue_script('pickadate', TEMPLATE_URI.'/js/plugins.min.js', 'jquery');
     792
     793        ob_start();
     794            ?>
     795            <script>
     796            jQuery('#<?= $this->makeID($name); ?>').pickadate({
     797                container: 'body',
     798                selectYears: '<?= $num_years; ?>',
     799                selectMonths: true,
     800                format: '<?= $format; ?>',
     801                formatSubmit: 'yyyy/mm/dd',
     802                hiddenName: true
     803                <?= $min; ?>
     804                <?= $max; ?>
     805            });
     806            </script>
     807            <?
     808        $html = ob_get_contents();
     809        ob_end_clean();
     810
     811        self::add_to_footer($html);
     812
     813        $this->inputs[$name] = $input;
     814
     815    }
     816
     817    /**
     818     * @param string $name
     819     * @param string $label
     820     * @param string|DateTime $initial
     821     * @param bool $required
     822     * @param array $attrs
     823     * @return void
     824    */
     825    public function timeSelect($name, $label, $initial=false, $required=NULL, $attrs=array())
     826    {
     827
     828        if (is_a($initial, 'DateTime')) {
     829            $initial = $initial->getTimestamp();
     830        }
     831
     832        $params = get_defined_vars();
     833        $params['type'] = __FUNCTION__;
     834        $this->addField($name, $params);
     835
     836        if (!$this->is_submitted && is_numeric($initial)) {
     837            $value = date('H:i', $initial);
     838        } elseif (!$this->submitted()) {
     839            $value = $initial;
     840        } elseif (!isset($_REQUEST[$name.'-hours']) || !isset($_REQUEST[$name.'-mins'])) {
     841            $value = false;
     842        } elseif ($_REQUEST[$name.'-hours'] != '--' && $_REQUEST[$name.'-mins'] != '--') {
     843            $value = $_REQUEST[$name.'-hours'].':'.$_REQUEST[$name.'-mins'];
     844        } else {
     845            $value = false;
     846        }
     847
     848        $this->setValue($name, $value);
     849
     850        if ($this->submitted()) {
     851
     852            if ($required && !$value) {
     853                $this->error($label.' not provided', $name);
     854            }
     855
     856        }
     857
     858        $attrs = $this->filterAttrs($attrs, $name);
     859        $fields = array('hours' => 'hh', 'mins' => 'mm');
     860        $input = '';
     861        $hours = array();
     862        $mins = array();
     863
     864        if ($value) {
     865            $field_values = array();
     866            $field_values['hours'] = strstr($value, ':', true);
     867            $field_values['mins'] = str_replace(':', '', strstr($value, ':', false));
     868        }
     869
     870        if (isset($attrs['increments'])) {
     871            $increments = $attrs['increments'];
     872        } else {
     873            $increments = 15;
     874        }
     875
     876        for ($i = 0; $i <= 23; $i++) {
     877            $j = str_pad($i, 2, '0', STR_PAD_LEFT);
     878            $hours[$j] = $j;
     879        }
     880
     881        for ($i = 0; $i <= 59; $i = $i + $increments) {
     882            $j = str_pad($i, 2, '0', STR_PAD_LEFT);
     883            $mins[$j] = $j;
     884        }
     885
     886        foreach ($fields as $time_input => $default) {
     887
     888            $input_name = $name.'-'.$time_input;
     889            $input_id = '{input_id}-'.$time_input;
     890
     891            if ($value) {
     892                $field_value = $field_values[$time_input];
     893            }
     894
     895            $input .= '<select ';
     896            $input .= 'name="'.$input_name.'" ';
     897            $input .= 'id="'.$input_id.'" ';
     898            $input .= 'class="{error}" ';
     899            $input .= '>';
     900            $input .= "\n";
     901
     902            if (!$required) {
     903                $input .= '<option value="--">['.$default.']</option>';
     904                $input .= "\n";
     905            }
     906
     907            foreach (${$time_input} as $key => $text) {
     908
     909                if ($value && $key == $field_value) {
     910                    $selected = ' selected="selected"';
     911                } else {
     912                    $selected = '';
     913                }
     914
     915                $input .= '<option value="'.$key.'" '.$selected.'>'.$text.'</option>';
     916                $input .= "\n";
     917
     918            }
     919
     920            $input .= '</select>';
     921            $input .= "\n";
     922
     923        }
     924
     925        $this->inputs[$name] = $input;
     926
     927    }
     928
     929    /**
     930     * @param string $name
     931     * @param string $label
     932     * @param string $error_msg
     933     * @param bool $initial
     934     * @return void
     935    */
     936    public function confirm($name, $label, $error_msg='You must tick the confirm box', $initial=0)
     937    {
     938
     939        $options = array(
     940            1 => $label
     941        );
     942
     943        $this->checkboxes($name, '', $options, array($initial), false, array());
     944
     945        $value = $this->getValue($name);
     946        $value = reset($value);
     947        $value = intval($value);
     948        $this->setValue($name, $value);
     949
     950        if ($this->is_submitted && $value != 1) {
     951            $this->error($error_msg, $name);
     952        }
     953
     954    }
     955
     956    /**
     957     * @param string $name
     958     * @param string $label
     959     * @param string $initial
     960     * @param bool $required
     961     * @param array $attrs
     962     * @return void
     963    */
     964    public function yesno($name, $label, $initial=false, $required=NULL, $attrs=array())
     965    {
     966        $initial = intval($initial);
     967        $options = array(
     968            1 => 'Yes',
     969            0 => 'No'
     970        );
     971
     972        $this->radiobuttons($name, $label, $options, $initial, $required, $attrs);
     973    }
     974
     975    /**
     976     * @param string $name
     977     * @param string $label
     978     * @param string $initial
     979     * @param bool $required
     980     * @param array $attrs
     981     * @return void
     982    */
     983    public function dob($name, $label, $initial=false, $required=NULL, $attrs=array())
     984    {
     985
     986        $attrs['year_start'] = date('Y');
     987        $attrs['year_end'] = 1920;
     988
     989        $this->dateSelect($name, $label, $initial, $required, $attrs);
     990
     991    }
     992
     993    /**
     994     * @param string $name
     995     * @param string $label
     996     * @param string $initial
     997     * @param bool $required
     998     * @param array $attrs
     999     * @return void
     1000    */
     1001    public function dobPicker($name, $label, $initial=false, $required=NULL, $attrs=array())
     1002    {
     1003        $attrs['min'] = mktime(0, 0, 0, 1, 1, 1920);
     1004        $attrs['max'] = 'today';
     1005        $attrs['num_years'] = 999;
     1006
     1007        $this->datePicker($name, $label, $initial, $required, $attrs);
     1008    }
     1009
     1010    /**
     1011     * @param string $name
     1012     * @param string $label
     1013     * @param string $initial
     1014     * @param bool $required
     1015     * @param array $attrs
     1016     * @return void
     1017    */
     1018    public function gender($name, $label, $initial=false, $required=NULL, $attrs=array())
     1019    {
     1020        $options = array(
     1021            'MALE' => 'Male',
     1022            'FEMALE' => 'Female'
     1023        );
     1024
     1025        if (empty($attrs['use_radio'])) {
     1026            $this->select($name, $label, $options, $initial, $required, $attrs);
     1027        } else {
     1028            $this->radioButtons($name, $label, $options, $initial, $required, $attrs);
     1029        }
     1030    }
     1031
     1032    /**
     1033     * @param string $name
     1034     * @param string $label
     1035     * @param string $initial
     1036     * @param bool $required
     1037     * @param array $attrs
     1038     * @return void
     1039    */
     1040    public function salutation($name, $label, $initial=false, $required=NULL, $attrs=array())
     1041    {
     1042
     1043        $options = array(
     1044            'Mr' => 'Mr',
     1045            'Mrs' => 'Mrs',
     1046            'Miss' => 'Miss',
     1047            'Ms' => 'Ms'
     1048        );
     1049
     1050        $this->select($name, $label, $options, $initial, $required, $attrs);
     1051
     1052    }
     1053
     1054    /**
     1055     * @param string $name
     1056     * @param string $label
     1057     * @param string $initial
     1058     * @param bool $required
     1059     * @param array $attrs
     1060     * @return void
     1061    */
     1062    public function email($name, $label, $initial=false, $required=NULL, $attrs=array())
     1063    {
     1064
     1065        $params = get_defined_vars();
     1066        $params['type'] = __FUNCTION__;
     1067        $this->addInput($name, $params);
     1068
     1069        $value = $this->getValue($name);
     1070        $value = trim($value);
     1071        $this->setValue($name, $value);
     1072
     1073        if ($this->submitted()) {
     1074
     1075            if (!self::validate_email($value)) {
     1076                $this->error($field['label'].' is not a valid email address', $name, 'IGNORE');
     1077            }
     1078
     1079        }
     1080
     1081    }
     1082
     1083    /**
     1084     * @param string $name
     1085     * @param string $label
     1086     * @param string $label_2
     1087     * @param bool $required
     1088     * @param array $attrs
     1089     * @return void
     1090    */
     1091    public function emailConfirm($name, $label, $label_2, $required=NULL, $attrs=array())
     1092    {
     1093
     1094        $name_2 = $name.'_confirm';
     1095
     1096        $this->email($name, $label, '', $required, $attrs);
     1097        $this->email($name_2, $label_2, '', $required, $attrs);
     1098
     1099        $value_1 = $this->getValue($name);
     1100        $value_2 = $this->getValue($name_2);
     1101
     1102        if ($this->submitted()) {
     1103
     1104            if ($value_1 != $value_2) {
     1105                $this->error('The emails you entered do not match. Please try again', $name_2);
     1106            }
     1107
     1108        }
     1109
     1110    }
     1111
     1112    /**
     1113     * @param string $name
     1114     * @param string $label
     1115     * @param string $initial
     1116     * @param bool $required
     1117     * @param array $attrs
     1118     * @return void
     1119    */
     1120    public function url($name, $label, $initial=false, $required=NULL, $attrs=array())
     1121    {
     1122
     1123        if (isset($_REQUEST[$name])) {
     1124            $_REQUEST[$name] = trim($_REQUEST[$name]);
     1125        } elseif (!$initial) {
     1126            $initial = 'http://';
     1127        }
     1128
     1129        $params = get_defined_vars();
     1130        $params['type'] = 'text';
     1131        $this->addInput($name, $params);
     1132
     1133        $value = $this->getValue($name);
     1134
     1135        if ($value == 'http://') {
     1136            $value = false;
     1137            $this->setValue($name, $value);
     1138        }
     1139
     1140        if ($this->submitted()) {
     1141
     1142            if ($required && !$value) {
     1143                $this->error($label.' not provided', $name);
     1144            }
     1145
     1146        }
     1147
     1148    }
     1149
     1150    /**
     1151     * @param string $name
     1152     * @param string $label
     1153     * @param string $initial
     1154     * @param bool $required
     1155     * @param array $attrs
     1156     * @return void
     1157    */
     1158    public function number($name, $label, $initial='', $required=NULL, $attrs=array())
     1159    {
     1160
     1161        $params = get_defined_vars();
     1162        $params['type'] = __FUNCTION__;
     1163        $this->addInput($name, $params);
     1164
     1165        $value = $this->getValue($name);
     1166
     1167        if ($this->submitted()) {
     1168
     1169            if ($required && !intval($value)) {
     1170                $this->error($label.' cannot be zero', $name);
     1171            }
     1172
     1173            if ($value && !is_numeric($value)) {
     1174                $this->error($label.' must be numeric', $name);
     1175            }
     1176
     1177            if (isset($attrs['min']) && $value < $attrs['min']) {
     1178                $this->error(sprintf('%s is below the minimum value', $label), $name);
     1179            }
     1180
     1181            if (isset($attrs['max']) && $value > $attrs['max']) {
     1182                $this->error(sprintf('%s is above the maximum value', $label), $name);
     1183            }
     1184
     1185        }
     1186
     1187    }
     1188
     1189    /**
     1190     * @param string $name
     1191     * @param string $label
     1192     * @param string $initial
     1193     * @param bool $required
     1194     * @param array $attrs
     1195     * @return void
     1196    */
     1197    public function phone($name, $label, $initial='', $required=NULL, $attrs=array())
     1198    {
     1199
     1200        $params = get_defined_vars();
     1201        $params['type'] = 'text';
     1202        $this->addInput($name, $params);
     1203
     1204        $value = $this->getValue($name);
     1205
     1206        if ($this->submitted()) {
     1207
     1208            if (strlen($value) > 0 && preg_match('/[A-Za-z]+/', $value)) {
     1209                $msg = sprintf('%s is not a valid phone number', $value);
     1210                $this->error($msg, $name, 'IGNORE');
     1211            }
     1212
     1213        }
     1214
     1215    }
     1216
     1217    /**
     1218     * @param string $group_name
     1219     * @param string $label
     1220     * @param array $settings
     1221     * @param array $initial
     1222     * @param bool $required
     1223     * @param array $attrs
     1224     * @return void
     1225    */
     1226    public function settings($group_name, $group_label, $settings, $initial=array(), $required=NULL, $attrs=array())
     1227    {
     1228
     1229        $initial = (array)$initial;
     1230        $this->checkboxes($group_name, $group_label, $settings, $initial, false, $attrs);
     1231        $value = $this->getValue($group_name);
     1232
     1233        if ($this->submitted()) {
     1234
     1235            foreach ($settings as $name => $label) {
     1236
     1237                if (in_array($name, $value)) {
     1238                    $this->setValue($name, true);
     1239                } else {
     1240                    $this->setValue($name, false);
     1241                }
     1242
     1243            }
     1244
     1245            unset($this->values[$group_name]);
     1246
     1247        }
     1248
     1249    }
     1250
     1251    /**
     1252     * @param string $html
     1253     * @return void
     1254     */
     1255    public function html($html)
     1256    {
     1257        end($this->inputs);
     1258        $last_input = key($this->inputs);
     1259
     1260        if ($last_input) {
     1261            $this->html[$last_input]['after'][] = $html;
     1262        } else {
     1263            $last_input = '__start__';
     1264            $this->html[$last_input]['before'][] = $html;
     1265        }
     1266
     1267    }
     1268
     1269    /**
     1270     * @param string $html
     1271     * @return void
     1272     */
     1273    public function prepend($html)
     1274    {
     1275        $this->html['__start__']['before'][] = $html;
     1276    }
     1277
     1278    /**
     1279     * @param string $input_name
     1280     * @param string $html
     1281     * @return void
     1282     */
     1283    public function before($input_name, $html)
     1284    {
     1285        $this->html[$input_name]['before'][] = $html;
     1286    }
     1287
     1288    /**
     1289     * @param string $input_name
     1290     * @param string $html
     1291     * @return void
     1292     */
     1293    public function after($input_name, $html)
     1294    {
     1295        $this->html[$input_name]['after'][] = $html;
     1296    }
     1297
     1298    /**
     1299     * @param string $name
     1300     * @return array
     1301     */
     1302    public function getField($name)
     1303    {
     1304        if (isset($this->fields[$name])) {
     1305            return $this->fields[$name];
     1306        } else {
     1307            return false;
     1308        }
     1309    }
     1310
     1311    /**
     1312     * @param string $field
     1313     * @return mixed
     1314     */
     1315    public function getValue($field)
     1316    {
     1317        return $this->values[$field];
     1318    }
     1319
     1320    /**
     1321     * @param string $field
     1322     * @param string $value
     1323     * @return void
     1324     */
     1325    public function setValue($field, $value)
     1326    {
     1327        //TODO$value = Filter::purify($value);
     1328        $this->values[$field] = $value;
     1329    }
     1330
     1331    /**
     1332     * @return bool
     1333     */
     1334    public function submitted()
     1335    {
     1336        return $this->is_submitted;
     1337    }
     1338
     1339    /**
     1340     * @return bool
     1341     */
     1342    public function success()
     1343    {
     1344        return $this->has_success;
     1345    }
     1346
     1347    /**
     1348     * @param string $msg
     1349     * @param string $key
     1350     * @param bool $ignore
     1351     * @return void
     1352     */
     1353    public function error($msg, $key=false, $ignore=false)
     1354    {
     1355
     1356        $this->has_success = false;
     1357
     1358        if ($key && !isset($this->errors[$key])) {
     1359            $this->errors[$key] = $msg;
     1360        } elseif (!$ignore) {
     1361            $this->errors[] = $msg;
     1362        }
     1363
     1364    }
     1365
     1366    /**
     1367     * @param Exception $Exception
     1368     * @param string $key
     1369     * @param bool $ignore
     1370     * @return void
     1371     */
     1372    public function exception($Exception, $key=false, $ignore=false)
     1373    {
     1374        $msg = $Exception->getMessage();
     1375        $this->error($msg, $key, $ignore);
     1376    }
     1377
     1378    /**
     1379     * @param string $label
     1380     * @param array $attrs
     1381     * @return void
     1382     */
     1383    public function submit($label, $attrs=array())
     1384    {
     1385        $html = '<div class="'.$this->submit_wrap.'">';
     1386        $html .= '<button type="submit" class="{class}">'.$label.'</button>';
     1387        $html .= '{append}';
     1388        $html .= '</div>';
     1389        $html .= "\n";
     1390
     1391        if (isset($attrs['append'])) {
     1392            $html = str_replace('{append}', $attrs['append'], $html);
     1393        } else {
     1394            $html = str_replace('{append}', '', $html);
     1395        }
     1396
     1397        if (isset($attrs['class'])) {
     1398            $html = str_replace('{class}', $attrs['class'], $html);
     1399        } else {
     1400            $html = str_replace('{class}', '', $html);
     1401        }
     1402
     1403        $this->inputs['submit'] = $html;
     1404    }
     1405
     1406    /**
     1407     * @return void
     1408     */
     1409    public function display()
     1410    {
     1411
     1412        echo '<div id="'.$this->form_id.'">';
     1413        echo "\n";
     1414
     1415        $this->putErrors();
     1416        $this->putForm();
     1417
     1418        echo '</div>';
     1419        echo "\n";
     1420
     1421    }
     1422
     1423    /**
     1424     * @return void
     1425     */
     1426    public function open()
     1427    {
     1428
     1429        //make action url
     1430        $action = $this->action;
     1431        $action .= ($this->keep_gets ? QSTRING : '');
     1432        $action .= ($this->fragment ? '#'.$this->fragment : '');
     1433
     1434        //start form
     1435        echo '<form action="'.$action.'" ';
     1436        echo 'method="'.$this->method.'" ';
     1437        echo 'id="'.$this->form_id.'" ';
     1438        echo 'class="'.$this->form_class.'" ';
     1439        echo 'enctype="multipart/form-data">';
     1440        echo "\n";
     1441
     1442    }
     1443
     1444    /**
     1445     * @return void
     1446     */
     1447    public function close()
     1448    {
     1449        echo '</form>';
     1450        echo "\n";
     1451    }
     1452
     1453    /**
     1454     * @return void
     1455     */
     1456    public function putErrors()
     1457    {
     1458
     1459        if (!$this->errors) {
     1460            return false;
     1461        }
     1462
     1463        $html = '<div class="'.$this->error_wrap.'">'."\n";
     1464        $html .= '<ul>'."\n";
     1465
     1466        foreach ($this->errors as $msg) {
     1467            $html .= '<li>'.self::esc_html($msg).'</li>'."\n";
     1468        }
     1469
     1470        $html .= '</ul>'."\n";
     1471        $html .= '</div>'."\n";
     1472
     1473        echo $html;
     1474
     1475    }
     1476
     1477    /**
     1478     * @return void
     1479     */
     1480    public function putForm()
     1481    {
     1482        //open form
     1483        $this->open();
     1484
     1485        //put hidden
     1486        $this->putHidden();
     1487
     1488        //add html
     1489        if (isset($this->html['__start__']['before'])) {
     1490            foreach ($this->html['__start__']['before'] as $html_bit) {
     1491                echo $html_bit."\n";
     1492            }
     1493        }
     1494
     1495        //put fields
     1496        foreach ($this->fields as $name => $params) {
     1497            $this->putField($name);
     1498        }
     1499
     1500        //put submit
     1501        if (isset($this->inputs['submit'])) {
     1502            $this->putField('submit');
     1503        }
     1504
     1505        //close form
     1506        $this->close();
     1507
     1508    }
     1509
     1510    /**
     1511     * @return void
     1512     */
     1513    public function putHidden()
     1514    {
     1515
     1516        $html = '<div style="display:none">'."\n";
     1517
     1518        //for forms with get method, add relevant hidden fields to match current query string
     1519        if ($this->keep_gets && $this->method == 'get') {
     1520
     1521            $qstring = trim(QSTRING, '?');
     1522            $vars = explode('&', $qstring);
     1523            $vars = array_filter($vars);
     1524
     1525            foreach ($vars as $var) {
     1526
     1527                $var = explode('=', $var);
     1528                $key = urldecode($var[0]);
     1529                $val = urldecode($var[1]);
     1530                $master_key = strstr($key, '[', true);
     1531
     1532                if (!$master_key) {
     1533                    $master_key = $key;
     1534                }
     1535
     1536                if (isset($this->fields[$master_key]) || isset($this->hidden[$master_key])) {
     1537                    continue; //skip fields that exist in this form
     1538                }
     1539
     1540                $html .= '<input type="hidden" name="'.$key.'" value="'.$val.'">'."\n";
     1541
     1542            }
     1543
     1544        }
     1545
     1546        foreach ($this->hidden as $name => $value) {
     1547            if (!is_scalar($value)) {
     1548                $value = '';
     1549            }
     1550
     1551            $html .= '<input type="hidden" name="'.$name.'" value="'.$value.'">'."\n";
     1552        }
     1553
     1554        $html .= '</div>'."\n";
     1555
     1556        echo $html;
     1557
     1558    }
     1559
     1560    /**
     1561     * @param string $name
     1562     * @return void
     1563     */
     1564    public function putField($name)
     1565    {
     1566        $html = '';
     1567
     1568        if (isset($this->html[$name]['before'])) {
     1569            foreach ($this->html[$name]['before'] as $html_bit) {
     1570                $html .= $html_bit."\n";
     1571            }
     1572        }
     1573
     1574        if ($name == 'submit') {
     1575            $html .= $this->inputs[$name];
     1576        } elseif (empty($this->fields[$name])) {
     1577            return;
     1578        } else {
     1579
     1580            if (empty($this->fields[$name]['attrs']['lang'])) {
     1581                $data_lang = '';
     1582            } else {
     1583                $data_lang = 'data-lang="'.$this->fields[$name]['attrs']['lang'].'"';
     1584            }
     1585
     1586            $label_html = $this->putLabel($name, false);
     1587            $input_html = $this->putInput($name, false);
     1588            $helper_html = $this->putHelper($name, false);
     1589            $type = $this->fields[$name]['type'];
     1590            $type_modifier = '__'.strtolower($type);
     1591
     1592            $html .= '<div class="'.$this->field_wrap.' '.$type_modifier.'" '.$data_lang.'>'."\n";
     1593            $html .= '{label}';
     1594            $html .= '<div class="'.$this->input_wrap.'">';
     1595            $html .= '{input}';
     1596            $html .= '</div>';
     1597            $html .= '{helper}'."\n";
     1598            $html .= '</div>'."\n";
     1599
     1600            $html = str_replace('{label}', $label_html, $html);
     1601            $html = str_replace('{input}', $input_html, $html);
     1602            $html = str_replace('{helper}', $helper_html, $html);
     1603        }
     1604
     1605        if (isset($this->html[$name]['after'])) {
     1606            foreach ($this->html[$name]['after'] as $html_bit) {
     1607                $html .= $html_bit."\n";
     1608            }
     1609        }
     1610
     1611        echo $html;
     1612
     1613    }
     1614
     1615    /**
     1616     * @param string $name
     1617     * @param bool $echo
     1618     * @return string
     1619     */
     1620    public function putLabel($name, $echo=true)
     1621    {
     1622
     1623        //make id
     1624        $input_id = $this->makeID($name);
     1625
     1626        //error class
     1627        if (isset($this->errors[$name])) {
     1628            $error_class = $this->error_class;
     1629        } else {
     1630            $error_class = '';
     1631        }
     1632
     1633        //required html
     1634        if (empty($this->fields[$name]['required'])) {
     1635            $required_html = '';
     1636        } else {
     1637            $required_html = ' <span class="'.$this->required_wrap.'">*</span>';
     1638        }
     1639
     1640        //label text
     1641        if (isset($this->labels[$name])) {
     1642            $label_text = $this->labels[$name];
     1643        } else {
     1644            $label_text = $this->fields[$name]['label'];
     1645        }
     1646
     1647        //sublabel
     1648        if (isset($this->fields[$name]['attrs']['sublabel'])) {
     1649            $sublabel = $this->fields[$name]['attrs']['sublabel'];
     1650        } elseif (isset($this->sublabels[$name])) {
     1651            $sublabel = $this->sublabels[$name];
     1652        } else {
     1653            $sublabel = false;
     1654        }
     1655
     1656        if ($sublabel) {
     1657            $sublabel_html = '<span class="'.$this->sublabel_wrap.'">';
     1658            $sublabel_html .= $sublabel;
     1659            $sublabel_html .= '</span>';
     1660        } else {
     1661            $sublabel_html = '';
     1662        }
     1663
     1664        //label
     1665        $html = '<div class="'.$this->label_wrap.'">';
     1666        $html .= '<label for="{input_id}" class="{error}">';
     1667        $html .= '{label_text}';
     1668        $html .= '{label_required}';
     1669        $html .= '</label>';
     1670        $html .= '{sublabel}';
     1671        $html .= '</div>';
     1672        $html .= "\n";
     1673
     1674        $html = str_replace('{input_id}', $input_id, $html);
     1675        $html = str_replace('for=""', '', $html); //remove blank for=""
     1676        $html = str_replace('{error}', $error_class, $html);
     1677        $html = str_replace('{label_text}', $label_text, $html);
     1678        $html = str_replace('{label_required}', $required_html, $html);
     1679        $html = str_replace('{sublabel}', $sublabel_html, $html);
     1680
     1681        if ($echo) {
     1682            echo $html;
     1683        } else {
     1684            return $html;
     1685        }
     1686
     1687    }
     1688
     1689    /**
     1690     * @param string $name
     1691     * @param bool $echo
     1692     * @return string
     1693     */
     1694    public function putInput($name, $echo=true)
     1695    {
     1696
     1697        //make id
     1698        $input_id = $this->makeID($name);
     1699
     1700        //error class
     1701        if (isset($this->errors[$name])) {
     1702            $error_class = $this->error_class;
     1703        } else {
     1704            $error_class = '';
     1705        }
     1706
     1707        $html = $this->inputs[$name];
     1708        $html = str_replace('{input_id}', $input_id, $html);
     1709        $html = str_replace('{error}', $error_class, $html);
     1710
     1711        if ($echo) {
     1712            echo $html;
     1713        } else {
     1714            return $html;
     1715        }
     1716
     1717    }
     1718
     1719    /**
     1720     * @param string $name
     1721     * @param bool $echo
     1722     * @return string
     1723     */
     1724    public function putHelper($name, $echo=true)
     1725    {
     1726
     1727        if (isset($this->fields[$name]['attrs']['helper'])) {
     1728            $helper_text = $this->fields[$name]['attrs']['helper'];
     1729        } elseif (isset($this->helpers[$name])) {
     1730            $helper_text = $this->helpers[$name];
     1731        } else {
     1732            $helper_text = false;
     1733        }
     1734
     1735        if ($helper_text) {
     1736
     1737            $html = '<div class="'.$this->helper_wrap.'">';
     1738            $html .= '<i class="'.$this->helper_wrap.'-icon">i</i>';
     1739            $html .= '<span class="'.$this->helper_wrap.'-text">';
     1740            $html .= '{helper_text}';
     1741            $html .= '</span>';
     1742            $html .= '</div>';
     1743
     1744            $html = str_replace("{helper_text}", $helper_text, $html);
     1745
     1746        } else {
     1747            $html = '';
     1748        }
     1749
     1750        if ($echo) {
     1751            echo $html;
     1752        } else {
     1753            return $html;
     1754        }
     1755
     1756    }
     1757
     1758    /**
     1759     * @param string $name
     1760     * @return string
     1761     */
     1762    protected function makeID($name)
     1763    {
     1764        return $this->form_id.'-'.$name;
     1765    }
     1766
     1767    /**
     1768     * @param array $attrs
     1769     * @param string $name
     1770     * @return array
     1771     */
     1772    protected function filterAttrs($attrs, $name)
     1773    {
     1774        if (isset($this->fields[$name]['label'])) {
     1775            $label = $this->fields[$name]['label'];
     1776        } else {
     1777            $label = '';
     1778        }
     1779
     1780        if (isset($attrs['placeholder'])) {
     1781
     1782            if ($attrs['placeholder'] === true) {
     1783                $attrs['placeholder'] = $label;
     1784            } else {
     1785                //do nothing if manual placeholder
     1786            }
     1787
     1788        } elseif (isset($this->placeholders[$name])) {
     1789            $attrs['placeholder'] = $this->placeholders[$name];
     1790        } elseif ($this->placeholder_all) {
     1791            $attrs['placeholder'] = $label;
     1792        }
     1793
     1794        return $attrs;
     1795    }
     1796
     1797    /**
     1798     * @param string $name
     1799     * @return bool
     1800     */
     1801    public function isRequired($name)
     1802    {
     1803        $field = $this->getField($name);
     1804
     1805        if (!$field) {
     1806            return;
     1807        } elseif ($field['required'] === NULL) {
     1808            return $this->require_all;
     1809        } else {
     1810            return $field['required'];
     1811        }
     1812    }
     1813
     1814    /**
     1815     * @param string $key
     1816     * @param array $attrs
     1817     * @param mixed $default
     1818     * @return mixed
     1819     */
     1820    protected static function make_attr($key, $attrs, $default=false)
     1821    {
     1822
     1823        if (isset($attrs[$key])) {
     1824            return ' '.$key.'="'.$attrs[$key].'"';
     1825        } else if ($default) {
     1826            return ' '.$key.'="'.$default.'"';
     1827        } else {
     1828            return '';
     1829        }
     1830
     1831    }
     1832
     1833    /**
     1834     * @param string $string
     1835     * @return string
     1836     */
     1837    protected static function esc_html($string)
     1838    {
     1839        return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
     1840    }
     1841
     1842    /**
     1843     * @todo Validate the email passed.
     1844     * @return bool
     1845     */
     1846    public static function validate_email($email)
     1847    {
     1848        return true;
     1849    }
     1850
     1851    /**
     1852     * @param string $html
     1853     * @return bool
     1854     */
     1855    public static function add_to_footer($html)
     1856    {
     1857
     1858        add_action('wp_footer', function() use ($html){
     1859            echo $html;
     1860        }, 100);
     1861
     1862    }
    18591863
    18601864}
  • wp-platform/trunk/classes/Model.php

    r1491664 r1504964  
    166166        } else {
    167167
    168             $q = "DELETE FROM `".escSQL($static::$table)."`
     168            $q = "DELETE FROM `".$static::$table."`
    169169                    WHERE id = ".intval($this->id)."";
    170170
     
    347347            if ($operator == 'LIKE') {
    348348                $val = '%'.$val.'%';
    349                 $q_where = " AND ".Security::escCol($column)." LIKE '".escSQL($val)."'";
     349                $q_where = " AND ".Security::escCol($column)." LIKE ".Security::escSQL($val)."";
    350350            } else {
    351                 $q_where = " AND ".Security::escCol($column)." = '".escSQL($val)."'";
     351                $q_where = " AND ".Security::escCol($column)." = ".Security::escSQL($val)."";
    352352            }
    353353
  • wp-platform/trunk/classes/Widget.php

    r1487792 r1504964  
    55
    66    //protected static $shortcode; //abstract
     7    protected static $widgets = array();
    78
    89    /**
     
    2324
    2425    /**
     26    * @return void
     27    */
     28    public function footer()
     29    {
     30        //this is a placeholder
     31    }
     32
     33    /**
    2534    * @param array $attrs
    2635    * @return void
    2736    */
    28     public function generate($attrs=array()) {
     37    public function generate($attrs=array())
     38    {
     39        $attrs = (array)$attrs;
    2940
    3041        foreach ($attrs as $key => $val) {
     
    3849        $this->prepare();
    3950        $this->display();
    40 
    4151    }
    4252
     
    4757    {
    4858        $shortcode = static::$shortcode;
    49         $Widget = new static();
    50         add_shortcode($shortcode, array($Widget, 'generate'));
     59        $widget = new static();
     60        add_shortcode($shortcode, array($widget, 'generate'));
     61        self::$widgets[$shortcode] = $widget;
    5162    }
    5263
  • wp-platform/trunk/plugin.php

    r1492384 r1504964  
    22/**
    33 * Plugin Name: WP-Platform
    4  * Version: 1.1.1
     4 * Version: 1.1.2
    55 * Description: Provides platform to allow developers to build bespoke functionality in an MVC and OOP fashion
    66 */
Note: See TracChangeset for help on using the changeset viewer.