Issues (565)

submit/AdminPageFramework_FieldType_submit.php (1 issue)

1
<?php
2
/**
3
 * Admin Page Framework
4
 * 
5
 * http://admin-page-framework.michaeluno.jp/
6
 * Copyright (c) 2013-2022, Michael Uno; Licensed MIT
7
 * 
8
 */
9
10
/**
11
 * Defines the `submit` field type.
12
 * 
13
 * <h2>Field Definition Arguments</h2>
14
 * <h3>Field Type Specific Arguments</h3>
15
 * <ul>
16
 *     <li>**href** - (optional, string) the url(s) linked to the submit button.</li>
17
 *     <li>**redirect_url** - (optional, string) the url(s) redirected to after submitting the input form.</li>
18
 *     <li>**reset** - [2.1.2+] (optional, boolean|string|array) the option key to delete. Set 1 for the entire option. [3.5.3+] In order to reset a particular field that belongs to a section, set an array representing the dimensional keys such as `array( 'my_sectio_id', 'my_field_id' )`.</li>
19
 *     <li>**confirm** - [3.8.24+] (optional, string|array) A confirmation checkbox to be enabled. If non-empty value is set, it will appear. An empty string by default. An array of the following arguments is accepted.
20
 *         <ul>
21
 *             <li>**label** - (string) the checkbox label.</li>
22
 *             <li>**error** - (string) the error message to display when the user does not check it but presses the submit button.</li>
23
 *         </ul>
24
 *     </li>
25
 *     <li>**skip_confirmation** - [3.7.6+] (optional, boolean) Whether to skip confirmation. Default: `false`.</li>
26
 *     <li>**email** - [3.9.0+] deprecated Use the `contact` field type.
27
 *     <li>**save** - [3.9.0+] (optional, boolean) Whether to save the value of the button, which is usually the label text. Default: `false`.</li>
28
 *     </li>
29
 * </ul>
30
 * 
31
 * <h3>Common Field Definition Arguments</h3>
32
 * For common field definition arguments, see {@link AdminPageFramework_Factory_Controller::addSettingField()}.
33
 * 
34
 * <h2>Example</h2>
35
 * <code>
36
 *  array( 
37
 *      'field_id'          => 'submit_button_field',
38
 *      'title'             => __( 'Submit Button', 'admin-page-framework-loader' ),
39
 *      'type'              => 'submit',
40
 *      'save'              => false,
41
 *  )
42
 * </code>
43
 * <h3>Submit Button as a Link</h3>
44
 * <code>
45
 *  array( 
46
 *      'field_id'          => 'submit_button_link',
47
 *      'type'              => 'submit',
48
 *      'title'             => __( 'Link Button', 'admin-page-framework-loader' ),
49
 *      'label'             => 'WordPress',
50
 *      'href'              => 'https://wordpress.org',
51
 *      'attributes'        => array(
52
 *          'class'     => 'button button-secondary',     
53
 *          'title'     => __( 'Go to Google!', 'admin-page-framework-loader' ),
54
 *          'style'     => 'background-color: #C1DCFA;',
55
 *          'field'     => array(
56
 *              'style' => 'display: inline; clear: none;',
57
 *          ),
58
 *      ), 
59
 *  )
60
 * </code>
61
 * <h3>Download Button</h3>
62
 * <code>
63
 *  array( 
64
 *      'field_id'      => 'submit_button_download',
65
 *      'title'         => __( 'Download Button', 'admin-page-framework-loader' ),
66
 *      'type'          => 'submit',
67
 *      'label'         => __( 'Admin Page Framework', 'admin-page-framework-loader' ),
68
 *      'href'          => 'http://downloads.wordpress.org/plugin/admin-page-framework.latest-stable.zip',
69
 *  ) 
70
 * </code>
71
 * 
72
 * <h3>Redirect Button</h3>
73
 * Unlike the `href` argument, with the `redirect` argument, the form data will be saved and the user gets redirected.
74
 * <code>
75
 *  array( 
76
 *      'field_id'      => 'submit_button_redirect',
77
 *      'title'         => __( 'Redirect Button', 'admin-page-framework-loader' ),
78
 *      'type'          => 'submit',
79
 *      'label'         => __( 'Dashboard', 'admin-page-framework-loader' ),
80
 *      'redirect_url'  => admin_url(),
81
 *      'attributes'    => array(
82
 *          'class' => 'button button-secondary',
83
 *      ),
84
 *  )
85
 * </code>
86
 *  
87
 * <h3>Submit Button with an Image</h3>
88
 * Instead of a text label, an image can be used for the button.
89
 * <code>
90
 *  array( 
91
 *      'field_id'          => 'image_submit_button',
92
 *      'title'             => __( 'Image Submit Button', 'admin-page-framework-loader' ),
93
 *      'type'              => 'submit',
94
 *      'href'              => 'http://en.michaeluno.jp/donate',
95
 *      'attributes'        =>  array(
96
 *         'src'    => AdminPageFrameworkLoader_Registry::$sDirPath . '/asset/image/donation.gif',
97
 *         'alt'    => __( 'Submit', 'admin-page-framework-loader' ),
98
 *         'class'  => '',
99
 *      ),
100
 *  )
101
 * </code>
102
 *
103
 * <h3>Reset Button</h3>
104
 * With the `reset` argument, the user can reset stored form data.
105
 * <code>
106
 *  array( 
107
 *      'field_id'      => 'submit_button_reset',
108
 *      'title'         => __( 'Reset Button', 'admin-page-framework-loader' ),
109
 *      'type'          => 'submit',
110
 *      'label'         => __( 'Reset', 'admin-page-framework-loader' ),
111
 *      'reset'         => true,
112
 *      'attributes'    => array(
113
 *          'class' => 'button button-secondary',
114
 *      ),
115
 *  )
116
 * </code>
117
 * 
118
 * @image           http://admin-page-framework.michaeluno.jp/image/common/form/field_type/submit.png
119
 * @package         AdminPageFramework/Common/Form/FieldType
120
 * @since           2.1.5
121
 * @since           3.3.1       Changed to extend `AdminPageFramework_FieldType` from `AdminPageFramework_FieldType_Base`.
122
 */
123
class AdminPageFramework_FieldType_submit extends AdminPageFramework_FieldType {
124
    
125
    /**
126
     * Defines the field type slugs used for this field type.
127
     */
128
    public $aFieldTypeSlugs = array( 'submit', );
129
    
130
    /**
131
     * Defines the default key-values of this field type. 
132
     * 
133
     * @remark $_aDefaultKeys holds shared default key-values defined in the base class.
134
     */
135
    protected $aDefaultKeys = array(
136
        'redirect_url'  => null,
137
        'href'          => null,
138
        'reset'         => null, 
139
        'email'         => null,    // [3.3.0+] string of an email address to send to or it can be an array with the following keys.
140
        /* 
141
            array(
142
                'to'            => null,    // string|array     The email address to send to or an array representing the key structure of the submitted form data holding the value. The first key should be the section ID and the second key is the field ID.
143
                'subject'       => null,    // string|array     The email title or an array representing the key structure of the submitted form data holding the value. The first key should be the section ID and the second key is the field ID.
144
                'message'       => null,    // string|array     The email body or an array representing the key structure of the submitted form data holding the value. The first key should be the section ID and the second key is the field ID.
145
                'headers'       => null,    // string|array     The email header or an array representing the key structure of the submitted form data holding the value. The first key should be the section ID and the second key is the field ID.
146
                'attachments'   => null,    // string|array     The file path(s) or an array representing the key structure of the submitted form data holding the value. The first key should be the section ID and the second key is the field ID.
147
                'is_html'       => true,    // boolean  Whether the mail should be sent as an html text
148
                'from'          => null,    // the sender email or an array representing the key structure of the submitted form data holding the value. The first key should be the section ID and the second key is the field ID.
149
                'name'          => null,    // the sender name or an array representing the key structure of the submitted form data holding the value. The first key should be the section ID and the second key is the field ID.
150
            )
151
        */
152
        'confirm'       => '',
153
        'skip_confirmation' => false,   // 3.7.6+ For emails.
154
        'attributes'    => array(
155
            'class' => 'button button-primary',
156
        ),
157
        'save'          => false,       // 3.9.0+
158
    );    
159
160
    /**
161
     * @return array
162
     * @since  3.9.0
163
     */
164
    protected function getEnqueuingScripts() {
165
        return array(
166
            array(
167
                'handle_id'     => 'admin-page-framework-submit-field-type',
168
                'src'           => dirname( __FILE__ ) . '/js/submit.bundle.js',
169
                'in_footer'     => true,
170
                'dependencies'  => array( 'jquery', ),
171
            ),
172
        );
173
    }
174
175
    /**
176
     * Returns the output of the field type.
177
     * 
178
     * @since       2.1.5   Moved from `AdminPageFramework_FormField`.
179
     * @since       3.3.1   Changed from `_replyToGetField()`.
180
     * @internal
181
     * @param       array   $aField
182
     * @return      string
183
     */
184
    protected function getField( $aField ) {
185
        
186
        $aField                     = $this->___getFormattedFieldArray( $aField );
187
        $_aInputAttributes          = $this->_getInputAttributes( $aField );
188
        $_aLabelAttributes          = $this->___getLabelAttributes( $aField, $_aInputAttributes );
189
        $_aLabelContainerAttributes = $this->___getLabelContainerAttributes( $aField );
190
191
        return 
192
            $aField[ 'before_label' ]
193
            . "<div " . $this->getAttributes( $_aLabelContainerAttributes ) . ">"
194
                . $this->_getExtraFieldsBeforeLabel( $aField ) // this is for the import field type that cannot place file input tag inside the label tag.
195
                . "<label " . $this->getAttributes( $_aLabelAttributes ) . ">"
196
                    . $aField[ 'before_input' ]
197
                    . $this->_getExtraInputFields( $aField )
198
                    . "<input " . $this->getAttributes( $_aInputAttributes ) . " />" // this method is defined in the base class
199
                    . $aField[ 'after_input' ]
200
                . "</label>"
201
                . $this->___getConfirmationCheckbox( $aField )
202
            . "</div>"
203
            . $aField['after_label'];
204
        
205
    }
206
        /**
207
         * @param  array  $aField
208
         * @return string
209
         * @since  3.8.24
210
         */
211
        private function ___getConfirmationCheckbox( $aField ) {
212
            if ( empty( $aField[ 'confirm' ] ) ) {
213
                return '';
214
            }
215
            $_aConfirm    = is_string( $aField[ 'confirm' ] )
216
                ? array(
217
                    'label' => $aField[ 'confirm' ]
218
                )
219
                : $this->getAsArray( $aField[ 'confirm' ] );
220
            $_aConfirm    = $_aConfirm + array(
221
                'label' => $this->oMsg->get( 'submit_confirmation_label' ),
222
                'error' => $this->oMsg->get( 'submit_confirmation_error' ),
223
            );
224
            $_aAttributes = $this->getElementAsArray( $aField, array( 'attributes', 'confirm' ) );
225
            $_sInput      = $this->getHTMLTag(
226
                'input',
227
                array(
228
                    'type'       => 'checkbox',
229
                    'name'       => "{$aField[ 'input_id' ]}[confirm]",
230
                    'class'      => 'confirm-submit',
231
                    'value'      => 0, // unchecked by default
232
                    'data-error-message' => $_aConfirm[ 'error' ],
233
                ) + $_aAttributes
234
            );
235
            return "<p class='submit-confirm-container'><label>"
236
                   . $_sInput
237
                   . "<span>{$_aConfirm[ 'label' ]}</span>"
238
                . "</label></p>";
239
        }
240
241
        /**
242
         * Returns the formatted field definition array.
243
         *
244
         * @since       3.5.3
245
         * @param       array       $aField
246
         * @return      array       The formatted field definition array.
247
         * @internal
248
         */
249
        private function ___getFormattedFieldArray( array $aField ) {
250
            
251
            $aField[ 'label' ] = $aField[ 'label' ]
252
                ? $aField[ 'label' ] 
253
                : $this->oMsg->get( 'submit' );
254
            
255
            if ( isset( $aField[ 'attributes' ][ 'src' ] ) ) {
256
                $aField[ 'attributes' ][ 'src' ] = esc_url( $this->getResolvedSRC( $aField[ 'attributes' ][ 'src' ] ) );
257
            }            
258
            return $aField;
259
            
260
        }    
261
        /**
262
         * Returns the label attribute array.
263
         * 
264
         * @since       3.5.3
265
         * @return      array       The label attribute array.
266
         * @internal
267
         */            
268
        private function ___getLabelAttributes( array $aField, array $aInputAttributes ) {
269
            return array(
270
                'style' => $aField[ 'label_min_width' ] 
271
                    ? "min-width:" . $this->getLengthSanitized( $aField[ 'label_min_width' ] ) . ";" 
272
                    : null,
273
                'for'   => $aInputAttributes[ 'id' ],
274
                'class' => $aInputAttributes[ 'disabled' ] 
275
                    ? 'disabled' 
276
                    : null,
277
            );
278
        }
279
        /**
280
         * Returns the label container attribute array.
281
         * 
282
         * @since       3.5.3
283
         * @param       array   $aField
284
         * @return      array   The label container attribute array.
285
         * @internal
286
         */        
287
        private function ___getLabelContainerAttributes( array $aField ) {           
288
            return array(
289
                'style' => $aField[ 'label_min_width' ] || '0' === ( string ) $aField[ 'label_min_width' ]
290
                    ? "min-width:" . $this->getLengthSanitized( $aField[ 'label_min_width' ] ) . ";" 
291
                    : null,
292
                'class' => 'admin-page-framework-input-label-container'
293
                    . ' admin-page-framework-input-button-container'
294
                    . ' admin-page-framework-input-container',
295
            );
296
        }    
297
        /**
298
         * Returns the input attribute array.
299
         *
300
         * @param       array       $aField
301
         * @since       3.5.3
302
         * @since       3.9.0       Changed the visibility scope to `protected` as the `contact` field type extends it.
303
         * @return      array       The input attribute array.
304
         * @internal
305
         */
306
        protected function _getInputAttributes( array $aField ) {
307
            $_bIsImageButton    = isset( $aField[ 'attributes' ][ 'src' ] ) && filter_var( $aField[ 'attributes' ][ 'src' ], FILTER_VALIDATE_URL );
308
            $_sValue            = $this->_getInputFieldValueFromLabel( $aField );
309
            return array(
310
                    // the type must be set because child class including export will use this method; in that case, the export type will be assigned which input tag does not support
311
                    'type'  => $_bIsImageButton ? 'image' : 'submit', 
312
                    'value' => $_sValue,
313
                ) 
314
                + $aField[ 'attributes' ]
315
                + array(
316
                    'title' => $_sValue,
317
                    'alt'   => $_bIsImageButton ? 'submit' : '',
318
                );
319
        }
320
        
321
    /**
322
     * Returns extra output for the field.
323
     * 
324
     * This is for the import field type that extends this class. The import field type cannot place the file input tag inside the label tag that causes a problem in FireFox.
325
     * 
326
     * @since       3.0.0
327
     * @param       array   $aField
328
     * @return      string
329
     * @internal
330
     */
331
    protected function _getExtraFieldsBeforeLabel( &$aField ) {
332
        return '';     
333
    }
334
    
335
    /**
336
     * Returns the output of hidden fields for this field type that enables custom submit buttons.
337
     * @since       3.0.0
338
     * @internal
339
     * @param       array   $aField
340
     * @return      string
341
     */
342
    protected function _getExtraInputFields( &$aField ) {
343
        
344
        $_aOutput   = array();
345
        $_aOutput[] = $this->getHTMLTag( 
346
            'input',
347
            array(
348
                'type'  => 'hidden',
349
                'name'  => "__submit[{$aField[ 'input_id' ]}][input_id]",
350
                'value' => $aField[ 'input_id' ],
351
            )
352
        );
353
        $_aOutput[] = $this->getHTMLTag( 
354
            'input',
355
            array(
356
                'type'  => 'hidden',
357
                'name'  => "__submit[{$aField[ 'input_id' ]}][field_id]",
358
                'value' => $aField[ 'field_id' ],
359
            ) 
360
        );            
361
        $_aOutput[] = $this->getHTMLTag( 
362
            'input',
363
            array(
364
                'type'  => 'hidden',
365
                'name'  => "__submit[{$aField[ 'input_id' ]}][name]",
366
                'value' => $aField[ '_input_name_flat' ],
367
            ) 
368
        );         
369
        $_aOutput[] = $this->___getHiddenInput_SectionID( $aField );
370
        $_aOutput[] = $this->___getHiddenInputByKey( $aField, 'redirect_url' );       
371
        $_aOutput[] = $this->___getHiddenInputByKey( $aField, 'href' );       
372
        $_aOutput[] = $this->___getHiddenInput_Reset( $aField );
373
        $_aOutput[] = $this->_getHiddenInput_Email( $aField );
0 ignored issues
show
Deprecated Code introduced by
The function AdminPageFramework_Field..._getHiddenInput_Email() has been deprecated: 3.9.0 Use the `contact` field type. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

373
        $_aOutput[] = /** @scrutinizer ignore-deprecated */ $this->_getHiddenInput_Email( $aField );

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
374
        return implode( PHP_EOL, array_filter( $_aOutput ) );  
375
        
376
    }
377
        /**
378
         * Returns the hidden input tag for the section id argument.
379
         * 
380
         * @since       3.5.3
381
         * @internal
382
         * @return      string      the HTML input tag output for the section id argument.
383
         * @param       array       $aField
384
         */    
385
        private function ___getHiddenInput_SectionID( array $aField ) {
386
            return $this->getHTMLTag( 
387
                'input',
388
                array(
389
                    'type'  => 'hidden',
390
                    'name'  => "__submit[{$aField['input_id']}][section_id]",
391
                    'value' => isset( $aField['section_id'] ) && '_default' !== $aField['section_id'] 
392
                        ? $aField['section_id'] 
393
                        : '',
394
                ) 
395
            );                  
396
        }           
397
        /**
398
         * Returns the hidden input tag for the given key argument.
399
         * 
400
         * @since       3.5.3
401
         * @internal
402
         * @param       array       $aField
403
         * @param       string      $sKey
404
         * @return      string      the HTML input tag output for the given key argument.
405
         */        
406
        private function ___getHiddenInputByKey( array $aField, $sKey ) {
407
            return isset( $aField[ $sKey ] )
408
                ? $this->getHTMLTag( 
409
                    'input',
410
                    array(
411
                        'type'  => 'hidden',
412
                        'name'  => "__submit[{$aField['input_id']}][{$sKey}]",
413
                        'value' => $aField[ $sKey ],
414
                    ) 
415
                )
416
                : '';            
417
        }       
418
        /**
419
         * Returns the hidden input tag for the 'reset' argument.
420
         * 
421
         * @since       3.5.3
422
         * @internal
423
         * @param       array       $aField
424
         * @return      string      the HTML input tag output for the 'reset' argument.
425
         */        
426
        private function ___getHiddenInput_Reset( array $aField ) {
427
            if ( ! $aField[ 'reset' ] ) {
428
                return '';
429
            }
430
            return ! $this->_checkConfirmationDisplayed( $aField, $aField[ '_input_name_flat' ], 'reset' )
431
                ? $this->getHTMLTag( 
432
                    'input',
433
                    array(
434
                        'type'  => 'hidden',
435
                        'name'  => "__submit[{$aField['input_id']}][is_reset]",
436
                        'value' => '1',
437
                    ) 
438
                )
439
                : $this->getHTMLTag( 
440
                    'input',
441
                    array(
442
                        'type'  => 'hidden',
443
                        'name'  => "__submit[{$aField[ 'input_id' ]}][reset_key]",
444
                        'value' => is_array( $aField[ 'reset' ] )   // set the option array key to delete.
445
                            ? implode( '|', $aField[ 'reset' ] )
446
                            : $aField[ 'reset' ],
447
                    )
448
                );      
449
        }
450
        /**
451
         * Returns the hidden input tag for the 'email' argument.
452
         * 
453
         * @since       3.5.3
454
         * @internal
455
         * @param       array       $aField
456
         * @return      string      the HTML input tag output for the 'email' argument.
457
         * @deprecated  3.9.0       Use the `contact` field type.
458
         * @todo    When the `email` argument is completely removed, move this method to the `contact` field type class.
459
         */ 
460
        protected function _getHiddenInput_Email( array $aField ) {
461
            
462
            if ( empty( $aField[ 'email' ] ) ) {
463
                return '';
464
            }
465
            if ( in_array( 'submit', $this->aFieldTypeSlugs, true ) ) {
466
                $this->showDeprecationNotice( 'The <code>email</code> argument has been deprecated.', 'the <code>contact</code> field type' );
467
            }
468
469
            $_sTransientKey = 'apf_em_' . md5( $aField[ '_input_name_flat' ] . get_current_user_id() );
470
            $this->setTransient( 
471
                $_sTransientKey,
472
                array(
473
                    'nonce' => $this->getNonceCreated( 'apf_email_nonce_' . md5( ( string ) site_url() ), 86400 ),  // @todo the nonce is crated when the page is rendered so change this to when the form is submitted so that a shorter nonce lifespan can be set.
474
                ) + $this->getAsArray( $aField[ 'email' ] )
475
            );
476
            return ! $this->_checkConfirmationDisplayed( $aField, $aField[ '_input_name_flat' ], 'email' )
477
                ? $this->getHTMLTag( 
478
                    'input',
479
                    array(
480
                        'type'  => 'hidden',
481
                        'name'  => "__submit[{$aField[ 'input_id' ]}][confirming_sending_email]",
482
                        'value' => '1',
483
                    ) 
484
                )
485
                : $this->getHTMLTag( 
486
                    'input',
487
                    array(
488
                        'type'  => 'hidden',
489
                        'name'  => "__submit[{$aField[ 'input_id' ]}][confirmed_sending_email]",
490
                        'value' => '1',
491
                    ) 
492
                );                
493
        }
494
    
495
        /**
496
         * A helper function for the above `getSubmitField()` that checks if a reset confirmation message has been displayed or not when the `reset` key is set.
497
         *
498
         * @param       array   $aField
499
         * @param       string  $sFlatFieldName
500
         * @param       string  $sType
501
         * @return      boolean
502
         * @internal
503
         */
504
        protected function _checkConfirmationDisplayed( $aField, $sFlatFieldName, $sType='reset' ) {
505
                            
506
            switch( $sType ) {
507
                default:
508
                case 'reset':       // admin page framework _ reset confirmation
509
                    $_sTransientKey = 'apf_rc_' . md5( $sFlatFieldName . get_current_user_id() );
510
                    break;
511
                case 'email':       // admin page framework _ email confirmation
512
                    $_sTransientKey = 'apf_ec_' . md5( $sFlatFieldName . get_current_user_id() );   
513
                    break;
514
            }
515
            $_bConfirmed = ! ( false === $this->getTransient( $_sTransientKey ) && ! $aField['skip_confirmation'] );
516
            if ( $_bConfirmed ) {
517
                $this->deleteTransient( $_sTransientKey );
518
            }             
519
            return $_bConfirmed;
520
            
521
        }
522
523
    /*
524
     * Shared Methods 
525
     */
526
527
    /**
528
     * Retrieves the input field value from the label.
529
     * 
530
     * This method is similar to the above <em>getInputFieldValue()</em> but this does not check the stored option value.
531
     * It uses the value set to the <var>label</var> key. 
532
     * This is for submit buttons including export custom field type that the label should serve as the value.
533
     * 
534
     * @remark      The `submit`, `import`, and `export` field types use this method.
535
     * @since       2.0.0
536
     * @since       2.1.5       Moved from `AdminPageFramwrork_InputField`. Changed the scope to protected from private. Removed the second parameter.
537
     * @internal
538
     * @param       array   $aField
539
     */ 
540
    protected function _getInputFieldValueFromLabel( $aField ) {    
541
        
542
        // If the value key is explicitly set, use it. But the empty string will be ignored.
543
        if ( isset( $aField[ 'value' ] ) && $aField[ 'value' ] != '' ) { 
544
            return $aField[ 'value' ]; 
545
        }
546
        
547
        if ( isset( $aField[ 'label' ] ) ) { 
548
            return $aField[ 'label' ]; 
549
        }
550
        
551
        // If the default value is set,
552
        if ( isset( $aField[ 'default' ] ) ) { 
553
            return $aField[ 'default' ]; 
554
        }
555
        
556
    }
557
    
558
}