Add an input type file in booking form

WordPress Event Management, Calendars & Registration Forums General Question Add an input type file in booking form

This topic contains 13 replies, has 4 voices, and was last updated by  Stephen Harris 4 years, 3 months ago.

Viewing 14 posts - 1 through 14 (of 14 total)
  • Author
    Posts
  • #19728

    Hi

    Can I add an input type file in booking form ?
    The aim is to save 3 files and add them in attached files to the administrator email.

    If plugin can’t do it, which hook I better use to develop it ?

    Marc FRÈREBEAU
    #19765

    I see we should create new field type by derivate EO_Booking_Form_Element class.
    => http://wp-event-organiser.com/blog/tutorial/using-form-api-add-additional-fields/

    But This tuto doesn’t explain this part of the job… :-/
    What are the steps to create new file type as “file” ?

    Marc FRÈREBEAU
    #19805

    Hi Marc,

    Apologies for having not replied sooner, but this is just to acknowledge your question. This is quite an involved question so I hope to have an extensive answer for you.

    Creating a field with file type is only have the story as you then have to validate, and store the submitted data.

    Stephen Harris
    #19806

    Hi Stephen,

    Thanks for your answer.
    In fact I have explore extension files where the class EO_Booking_Form_Element_input to imitate construction.

    I see my field in the interface but it’s not finish… Her the code I beginning :

    class EO_Booking_Form_Element_File extends EO_Booking_Form_Element{
        
        static function get_type_name(){
            return 'Fichier';
        }
        
        function get_field_type(){
            return 'file';
        }
        
        function get_defaults(){
            return array(
                'label' => 'Fichier',
            );
        }
        
        function get_data(){
            return $this->get( 'data' );
        }
    
    }
    EO_Booking_Form_Element_Factory::register( 'file', 'EO_Booking_Form_Element_File' );
    
    class EO_Booking_Form_Element_File_View extends EO_Booking_Form_Element_View{
    
        function render(){
            ob_start();
            include( get_stylesheet_directory() . '/templates/EO_Booking_Form_Element_File.php' );
            $html = ob_get_contents();
            ob_end_clean();
            return $html;
        }
        
        function get_value(){
            return $this->element->get_value();
        }
    }
    EO_Booking_Form_Element_View_Factory::register ( 'file', 'EO_Booking_Form_Element_File_View' );
    
    EO_Booking_Form_Controller::register( 'file','Fichier', 'EO_Booking_Form_Element_File', get_stylesheet_directory() . '/templates/EO_Booking_Form_Element_File.php' );
    
    

    And I create this template :

    <?php include( eo_locate_template( 'eo-booking-form-label.php' ) ); ?>
    
    <input
        type="<?php echo esc_attr( $this->element->get_field_type() );?>"
        id="<?php echo esc_attr( 'eo-booking-field-'.$this->element->id );?>"
        name="<?php echo esc_attr( $this->get_name() );?>"
        class="<?php echo esc_attr( $this->get_class() );?>"
        style="<?php echo esc_attr( $this->element->get( 'style' ) );?>"
    
    <?php if( $this->element->is_required() ):?>
        required="required"
    <?php endif;?>
    
    <?php if( $this->element->get_data() ): ?>
        <?php foreach( $this->element->get_data() as $key => $attr_value ): ?>
            data-<?php echo esc_attr( $key )?>="<?php echo esc_attr( $attr_value );?>"
        <?php endforeach;?>
    <?php endif;?>
    
    />
    
    <?php include( eo_locate_template( 'eo-booking-form-description.php' ) ); ?>
    
    <?php include( eo_locate_template( 'eo-booking-form-errors.php' ) ); ?>
    

    I know it miss function is_valid( $input ) on my EO_Booking_Form_Element_File class… And after I’ll should to add data in the mail…

    I think I have to create some other templates to have some configuration fields in admin. And my controler register command should be false…

    The difficult is to not have some guide line to not forget some steps… I discover them I discovered progressively.

    Marc FRÈREBEAU
    #19849

    Marc,

    Feel free to ask for me to go in more detail, but here’s the broad picture (with comments where I’ve omitted details specific to your use case):

    1. Enable file uploads on the booking form
    The booking form by default only supports $_POST data. To support file uploads you’ll need to add the attribute enctype="multipart/form-data" to the <form> tag in templates/eo-booking-form.php template:

    <form enctype="multipart/form-data ...>
      ...
    </form>
    

    Copy that file to the root directory of your theme and edit there so it survives updates to the plug-in.

    2. Declare the Element class
    This is similar to your class but I’ve extended the EO_Booking_Form_Element_Input class – this is for convenience as I no longer have to declare a view. Views are registered as you have shown, but if my element doesn’t have a view it will proceed through the class’ ancestors until it finds a View. In this case, the parent is EO_Booking_Form_Element_Input which does have a view class: EO_Booking_Form_Element_Input_View – and this just so happens to be exactly what I need: an <input> with a configurable type (which I set below in get_field_type())

    Of course if you wish you can register your own View class if you wish.

    class EO_Booking_Form_Element_File extends EO_Booking_Form_Element_Input{
    
        static function get_type_name(){
            return 'Fichier';
        }
    
        function get_field_type(){
            return 'file';
        }
    
        function get_defaults(){
            return array(
                'label' => 'Fichier',
            );
        }
    
        function get_data(){
            return $this->get( 'data' );
        }
    
        function validate( $input ) {
    
            //@see http://php.net/manual/en/reserved.variables.files.php for details
            $file = array(
                'tmp_name' => $_FILES['eventorganiser']['tmp_name']['booking']['file'],
                'name'     => $_FILES['eventorganiser']['name']['booking']['file'],
                'size'     => $_FILES['eventorganiser']['size']['booking']['file'],
                'error'    => $_FILES['eventorganiser']['error']['booking']['file'],
                'type'     => $_FILES['eventorganiser']['type']['booking']['file'],     
            );
    
            //Validate file, e.g. check type, check for errors, and check for size
            //PLease note that $file['type'] can be spoofed - its best to analyzie the contents of the file
    
            //if there is any error: $this->add_error( 'my-error-code', 'Error message' );
    
            //Otherwise set value
            $this->set_value( $file );
    
        }
    
        function save( $booking_id ) {
    
            $file = $this->get_value(); //returns the array set above in validate().
    
            //You can now upload the file
            //@see https://codex.wordpress.org/Function_Reference/wp_handle_upload
            $_file = wp_handle_upload( $file,  array( 'test_form' => false ), time() );         
    
            //Once the file is uploaded you could either
            //Store a reference to the file location in as booking meta,
            //Or use wp_insert_attachment and store a reference to the attacment ID in booking meta
    
            //In either case, to add booking meta
            //update_post_meta( $booking_id, 'my_meta_key', 'my_value' );
    
        }
    
    }
    

    I’ve simply added two methods to the class. First is validate() – this is where you should perform any checks on the file. You might want to consider:

    • Analysing the type and content of the file to prevent any uploads of malicious files
    • Imposing a size limit on the file
    • Checking the error number: it should be 0 if all is well

    The function also sets the value of the element so that we can retrieve this later (i.e. in save()). (This really could/should be set earlier but this will suffice). To prevent the booking from proceeding and return the user to the booking page with an error message, simply add an error the element as shown.

    The second method is save( $booking_id ). This is triggered after the booking is made (not necessarily confirmed) and this where you should upload the file to the server. (wp_handle_upload() is good for that).

    You should then store a means of linking a file and a booking. You could do that by simply storing the file location as post meta. Or create an attachment for the uploaded file and store the attachment ID as a booking meta data. (Bookings are posts so you can use the usual post meta functions).

    3. Add to the form

    Please note that this is part of the API may change – you can alternatively programatically add the element the form.

    To do add the element to the form customiserL:

     EO_Booking_Form_Controller::register( 
         'file', //element type ID
         'Fichier', //Label for the form customiser
         'http://yoursite.com/url/to/backbone-model.js',  //url to customiser 'model'
         'http://yoursite.com/url/to/customiser-view.tmpl',//url to customiser view
         'advanced' //which metabox to add the button to: standard, advanced
     );
    

    The model ‘is’ your file element type in the customiser. It essentially stores the default values of an instance of that type.

    eo.bfc.Model.EOFormElementFile = eo.bfc.Model.EOFormElementInput.extend({
        defaults:{
            label: eo.gettext("Fichier"),
            name: eo.gettext("Fichier"),
            description: "",
            required: false,
            field_type: 'text',
            parent: 0,
        },
    });
    

    you could specify the settings, but we’ll just inherit the settings for input.

    The template is used to generate a preview of the element in the customiser. E.g. put the following in the .tmpl file:

    <label>{{label}}</label><# if( required ){ #><span class="required">*</span><#}#><br>
    <input type="file" disabled="disabled" />
    <# if( description ){ #><p class="description">{{description}}</p><#}#>
    

    Side remarks: Backbone is used for the Model and Views in the customiser and Underscore is used for template rendering.

    Stephen Harris
    #19867

    Hi Stephen,

    Thanks a lot for this complete answer.
    I have not had the opportunity to test… I’ll dig it tomorow.
    If it works well we could make a tutoriel to create somme new file types as this… 😉

    I’ll say you here when I’m ok. 🙂

    Marc FRÈREBEAU
    #19870

    Please do 🙂

    Stephen Harris
    #29873

    Hello Stephen,
    I’ve been trying out your instructions, I have the file button in the customizer, but when I click it I get “Unrecognized type”.
    The Backbone-model.js file is being read from the traces in the post params.
    Has anything changed since 2015 that I need to take into consideration?
    Any help would be gratefully recieved.

    Maude Picalausa
    #29918

    Have you definitely done the step:

     EO_Booking_Form_Controller::register( 
         'file', //element type ID
         'Fichier', //Label for the form customiser
         'http://yoursite.com/url/to/backbone-model.js',  //url to customiser 'model'
         'http://yoursite.com/url/to/customiser-view.tmpl',//url to customiser view
         'advanced' //which metabox to add the button to: standard, advanced
     );
    

    I would expect that error, if the field is not registered with the controller.

    Stephen Harris
    #38495

    Hi Stephen,
    first of all, thank you for the great plugin and your support. For a client i need to add a file upload to the bookingform as well and i was using your suggestion of this topic. I can see the new button in the backend of the booking form but i cannot add the button to the form. Nothing happens if i click on the it. In the console i get the error “Uncaught SyntaxError: Unexpected token ‘<‘ ” which is coming from the customiser-view.tmpl. I use the current version of WordPress 5.5 and the current plugin version.

    Do you have an idea how i could get the button to work properly?

    Thank you very much!

    Greetings,
    Denny

    kreevogmbh
    #38498

    Ah it should be the path to the .tmpl, not the URL.

    Stephen Harris
    #38504

    Thanks Stephen for your quick response. Even if i change url to path the error occurs still. The file is loaded, because if the path or url is wrong i get a 404 in the console. But it seems like that the .tmpl file is not rendered correct if the first char “<” is “unexpected”. I register the button now like this:
    EO_Booking_Form_Controller::register(
    'file', //element type ID
    'Fichier', //Label for the form customiser
    '/wp-content/themes/theme_name/backbone-model.js',
    '/wp-content/themes/theme_name/customiser-view.tmpl',
    'advanced' //which metabox to add the button to: standard, advanced
    );

    Can i do something else?

    Thx!

    kreevogmbh
    #38569

    Hi Stephen,
    could you please take a look why the solution is not working? I depend on the functionality of an upload button but the error still occurs if i click the button. You have any ideas why?

    Thank you for your help.

    kreevogmbh
    #38589

    Hi Denny,

    Reverting back to what you had, open the network tab of your browser console and try clicking the button to add the element to the form – you should see a HTTP request to admin-ajax.php, what is the response of that?

    Stephen Harris
Viewing 14 posts - 1 through 14 (of 14 total)
To enable me to focus on Pro customers, only users who have a valid license for the Pro add-on may post new topics or replies in this forum. If you have a valid license, please log-in or register an account using the e-mail address you purchased the license with. If you don't you can purchase one here. Or there's always the WordPress repository forum.