Performance issue

Forminator Forms
21 September, 2020 12:22:54
matlo
Topics: 2
Messages: 8
I am generating 3 PDFs from 2 templates and I am sending 3 emails. PDF 1 is sent within email 1 and 2. PDF 2 and 3 are sent withing email 3. I guess it doesn't matter how many times I sent generated PDFs since you probably cache the already generated PDFs.

My problem is that form submission while generating those 3 PDFs take on average 18s. Without generating them, submission takes around 3s. So it takes on average 5s to generate 1 PDF. Firstly, I thought it is because I use plenty of parameters (24 in template 1 and 12 in template 2). But then I tried it with empty templates. And the form submission still took more than 14s.

I also tried API2 in settings but the process was even slower. Since the whole process works through API, I am thinking if data transmission speed isn't a problem. My hosting is located in Slovakia. What do you think about it? Do you have any other idea where could be a problem?

I am also thinking about a workaround to generate emails and send PDFs asynchronously. In forminator hook, I could schedule cron job where I would generate PDF and then send emails using the wp_mail function. Similarly to this solution:
https://wordpress.stackexchange.com/questions/185295/how-to-make-wordpress-emails-async
I haven't done it before and I would rather avoid doing it this way. Also, I am not sure if e2pdf attach. shortcode is compatible with wp_mail function. And at this point, I wouldn't be using forminator extension at all to make the process easier.
21 September, 2020 13:05:05
E2Pdf
Support
Topics: 7
Messages: 3346
Hi,

If you are using different email actions, then it's matter, as by default E2Pdf generates PDFs for each email action separately. It generates PDF, attach it to mail and removes it from server after mail sent to not have any garbage in the system.

You can try to use "e2pdf-save" shortcode with "attachment" true and "overwrite" false attributes: [e2pdf-save id="1" overwrite="false" attachment="true" name="{submission_id}"]

* "name" attribute also must be unique for each submission, so you must be able to combine the name with {submission_id}, as in example above.

Shortcode will save PDF on your server, attach it to email, and will send. Next email will check if file exists and if yes, it will use the same file and will not do PDF regeneration.

Regarding ASYNC emails - we had some users who using it with some 3rd party plugins and actually for this was created shortcode above (e2pdf-save with attachment attribute) as WordPress requires file to exist on server to be attached. E2Pdf uses functionality of standard wp_mail function along with standard behavior of forms.

We remain at your service.
We would really appreciate your feedback at WordPress.org!
22 September, 2020 11:11:52
matlo
Topics: 2
Messages: 8
Hi,
thanks for advice, I used "save" shortcode and it helped a little bit since I am sending some PDFs mutliple times. But in the end, I am still generating 3 different files and whole submission process take 14s. And i also plan to add payment process to this form.

I was thinking about one more workaround, which might be more simple then using ASYNC emails. Before submitting this form, user must submit different form. And after submitting this "first" form I already have all infomation i need for generating PDFs, I am just not sending them to anybody yet. So I could generate all PDFs after submitting that first form and save them. But I need forminator filter or action which is fired after forms submission. So I could generate PDFs without blocking submission of the first form. Unfortunately I haven't find such a hook so far. Don't you know about some formiantor action or filter I could use for this workaround?
22 September, 2020 12:43:55
E2Pdf
Support
Topics: 7
Messages: 3346
Unfortunately even if you will move sending mails on the end of process, PHP will lock the page until all PDFs generated and sent. This must be done via cron job to avoid locking.

The process could looks like this, however it will require custom coding:

- You add some hidden field inside form which by default for example has '0' as default value.
- You add condition to send mail only if this hidden value is '1', so after first submission emails will not be sent.
- Via cron job you get entries which has this hidden value set to '0', you update this entries to '1' and rise sending email function. It must be possible to do with:

$forminator_mail_sender = new Forminator_CForm_Front_Mail();
$forminator_mail_sender->process_mail( $custom_form, $submitted_data, $entry, $pseudo_submitted_data );

- After mail sent you can update hidden value to 2, to be sure that email sent.

If you will use even async emails, form submission will be still locked until all PDFs generated and saved, as e2pdf shortcodes fires on 'forminator_custom_form_mail_admin_message' filter.


We would really appreciate your feedback at WordPress.org!
25 September, 2020 15:06:20
matlo
Topics: 2
Messages: 8
Thank you very much for your advice, Oleksandr. It really helped me, I appreciate it!

For anybody also implementing this feature, I have a few more insights:
Firstly I try to do it without getting entries from DB. I tried to pass all the data as args to wp_schedule_single_event, so the PDF generation starts right after form submission (I set timestamp to time()). Unfortunately, this solution was buggy. Sometimes the cron task executed more than once and sometimes it didn't execute at all. So I don't recommend doing it this way. In the end, I did it as Oleksandr recommended. But, for some reason, the cron task scheduled using wp_schedule_single_event still doesn't run sometimes. So I also used wp_schedule_event to run the process every 30 minutes to collect all "forgotten" entries and send emails.

For the arguments of process_mail function:
$custom_form can be created easily like this: $customForm = Forminator_Custom_Form_Model::model()->load(FORM_ID);
$submitted_data is just array of fields and their values e.g. array("hidden-1" => "some_value"), ..). It seems to be sufficent to pass just fields values you need for further evaluations (in hooks or conditions).
$entry is just the object you get from DB
$pseudo_submitted_data should be just same as $submitted_data. Don't forget this, it will not work without it.