PHPackages                             xpertbot/craft-wheelform - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. xpertbot/craft-wheelform

ActiveCraft-plugin

xpertbot/craft-wheelform
========================

Craft CMS 5 Form administrator with Database integration

4.0.4(7mo ago)6552.3k↓35.6%30[12 issues](https://github.com/xpertbot/craft-wheelform/issues)[10 PRs](https://github.com/xpertbot/craft-wheelform/pulls)3MITPHPCI passing

Since Mar 29Pushed 1mo ago2 watchersCompare

[ Source](https://github.com/xpertbot/craft-wheelform)[ Packagist](https://packagist.org/packages/xpertbot/craft-wheelform)[ RSS](/packages/xpertbot-craft-wheelform/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (3)Versions (138)Used By (3)

Wheel Form plugin for Craft CMS 5.x
===================================

[](#wheel-form-plugin-for-craft-cms-5x)

Free Form Builder with Database Integration, successor of Free Contact Form Plugin featured on [Straight Up Craft](https://straightupcraft.com/)

[![Screenshot](resources/img/form-entries.jpg)](resources/img/form-entries.jpg)

Craft CMS 4.x
-------------

[](#craft-cms-4x)

Use `composer require xpertbot/craft-wheelform "^3.2"`

Craft CMS 3.x
-------------

[](#craft-cms-3x)

Use `composer require xpertbot/craft-wheelform "^2.7"`

Requirements
------------

[](#requirements)

This plugin requires Craft CMS 5.0.0 or later

Installation
------------

[](#installation)

To install the plugin, follow these instructions.

1. Open your terminal and go to your Craft project:

    ```
     cd /path/to/project

    ```
2. Then tell Composer to load the plugin:

    ```
     composer require xpertbot/craft-wheelform

    ```
3. In the Control Panel, go to Settings → Plugins and click the “Install” button for Wheel Form.

Features
--------

[](#features)

- reCaptcha Validation
- Export CSV File
- Custom Email HTML Template
- Template variables for easy development
- Email Validation based on field type selected
- Form Field Type for sections
- Required Fields
- Checkbox options
- File extension restriction
- Honeypot Field
- Ajax and Redirect friendly
- Send Form submissions to multiple emails
- Advanced Permissions per form
- Reordering of fields
- Save Uploaded files to Asset Manager
- Multiple Translations
- Export / Import Fields between different websites
- Dynamic email notifications

Usage
-----

[](#usage)

After successful installation go to Plugin Settings and add the email you would like the forms to send `FROM`. As well as set other useful settings.

Forms are administered at the forms panel main settings. Set where this form should be submitting `TO` as well as name of the form.

Field Settings can be set as Required or not, for validation purposes.

Current Field types supported are:

- Text
- Textarea
- Email
- Number
- Checkboxes
- Radio
- Select
- Hidden
- File
- List
- HTML

Template Variables
------------------

[](#template-variables)

- wheelform

    - settings
    - form
        - recaptcha
        - open()
        - close()
        - fields
            - type
            - name
            - label
            - items
            - fieldClass
            - containerClass
            - required
            - order
            - value
            - options
            - displayLabel
        - entries
            - id
            - formId
            - fields
                - name
                - label
                - value
                - type
            - date
        - getErrors()
    - lastSubmission
        - id
        - formId
        - fields
            - name
            - label
            - value
            - type
- wheelformErrors (Array of errors based on field name, form, recaptcha, honeypot).
- values (Array of User submitted values based on field name).

Form Configuration Options
--------------------------

[](#form-configuration-options)

These are configuration opens you can pass to `wheelform.form` to configure your form.

- `id`: **Required** ID of the form being used.
- `redirect`: URL where form will redirect to after a successful submission.
- `registerScripts`: Boolean to load Scripts before `wheelform.open` call (This is useful for caching forms and templates). Defaults to False.
- `refreshCsrf`: Boolean to load Javascript that will refresh the CSRF token for the form on the current page (This is useful for caching forms and templates). In order for this to work `form.open()` needs to be outside the `{% cache %}` block.
- `submitForm`: Configuration options for the submitButton. Example:

```
{# SubmitButton options:
    "type" can be button, or input
    "html" attribute takes precedence over the other properties,
    "attributes" is an easy way to add attributes to the button, all attributes are optional #}

submitButton: {
    "type": "button",
    "label": "Send", // Text displayed for the button
    "attributes": { // Array of attributes for the Button. Same as Form
        "class": "btn btn-success",
        "id": "submit-btn",
        "data-submit": "Foo",
    },
    "html": "Custom Button", // Custom HTML Overwrittes any other options and will render it as final.
}
```

### Form.open() parameter options

[](#formopen-parameter-options)

- `action`: String to overwritte where the form submits to. This is useful if you need to overwrite it with Javascript. Defaults to empty string.
- `attributes`: {Key: Value} Array of Attributes for the current form. Defaults to empty array. Note: Form attributes take presedence over default values. Example:

```
{#
    - Special Attribute: `csrf`: {boolean}, enables/disables csrf token field, disable if you would like to implement your own csrf token generation. Example:
    {{ form.open('', {
        'csrf': false,
    }) }}
        {{ craft.blitz.csrfInput() }}
        ... Rest of form template ...
#}
```

- `method`: String to overwritte the form HTML `method` attribute. Defaults to "POST"

```
{{ form.open("", {
        'novalidate': 'novalidate',
        'id':'custom-form',
        'class': 'custom-form',
    }, "POST") }}
```

### Field Service options

[](#field-service-options)

- `getFileExtensions` If current Field Type is "file" you can retrieve the current "File Extension Restrictions" set on that field.

### Dynamic Email notifications

[](#dynamic-email-notifications)

- "Email Subject", "Submit Message", "User Notification Subject" and "User Notification Message" form settings can use dynamic field values by referencing the field "name" between square brackets. e.g. "You received a form submission from `[email]`" where `email` is the `name` of a field in your form.

Template Structure
------------------

[](#template-structure)

Your form template can look something like this:

```
{% macro errorList(errors) %}
    {% if errors %}

            {% for error in errors %}
                {{ error }}
            {% endfor %}

    {% endif %}
{% endmacro %}
{% from _self import errorList %}

{% set form = wheelform.form({
    id: 1,
    redirect: 'contact/thanks'
}) %}

{{ form.open() }}
    {{ wheelformErrors['form'] is defined ? errorList(wheelformErrors['form']) }}
    {{ wheelformErrors['recaptcha'] is defined ? errorList(wheelformErrors['recaptcha']) }}
    {{ wheelformErrors['honeypot'] is defined ? errorList(wheelformErrors['honeypot']) }}

    {% for field in form.fields %}
        {{ field.render() }}
        {{ wheelformErrors[field.name] is defined ? errorList(wheelformErrors[field.name]) }}
    {% endfor %}
{{ form.close() }}
```

Advanced templating:

```
{% macro errorList(errors) %}
    {% if errors %}

            {% for error in errors %}
                {{ error }}
            {% endfor %}

    {% endif %}
{% endmacro %}
{% from _self import errorList %}

{% set form = wheelform.form({
    id: 1,
    redirect: 'contact/thanks',
}) %}

{{ form.open() }}
    {{ wheelformErrors['form'] is defined ? errorList(wheelformErrors['form']) }}
    {{ wheelformErrors['recaptcha'] is defined ? errorList(wheelformErrors['recaptcha']) }}
    {{ wheelformErrors['honeypot'] is defined ? errorList(wheelformErrors['honeypot']) }}

    {% for field in form.fields %}
        {% switch field.type %}
            {% case "checkbox" %}

                {% for item in field.items %}
                {{item}}
                {% endfor %}

            {% case "radio" %}

                {% for item in field.items %}

                {{item}}
                {% endfor %}

            {% case "select" %}

                {% for item in field.items %}
                    {{item}}
                {% endfor %}

            {% case "file" %}

                    {{field.label}}

            {% case "textarea" %}

                    {{field.label}}
                    {{ values[field.name] ?? '' }}

            {% case "list" %}

                    {{field.label}}

                    //Javascript to handle adding fields

            {% default %}

                {{field.label}}

        {% endswitch %}
        {{ wheelformErrors[field.name] is defined ? errorList(wheelformErrors[field.name]) }}
    {% endfor %}
    {% if form.recaptcha %}

    {% endif %}

    Send

```

If you want to stick to HTML and not use the variables:

```
{% macro errorList(errors) %}
    {% if errors %}

            {% for error in errors %}
                {{ error }}
            {% endfor %}

    {% endif %}
{% endmacro %}

{% from _self import errorList %}

    {{ wheelformErrors['form'] is defined ? errorList(wheelformErrors['form']) }}

    {{ csrfInput() }}

    Your Name

    {{ wheelformErrors['name'] is defined ? errorList(wheelformErrors['name']) }}

    Your Email

    {{ wheelformErrors['email'] is defined ? errorList(wheelformErrors['email']) }}

    Phone

    {{ wheelformErrors['phone'] is defined ? errorList(wheelformErrors['phone']) }}

    Chocolate
    Vanilla
    Strawberry
    {{ wheelformErrors['favorite_topping'] is defined ? errorList(wheelformErrors['favorite_topping']) }}

    Message
    {{ values['message'] ?? '' }}
    {{ wheelformErrors['message'] is defined ? errorList(wheelformErrors['message']) }}

    {# if using recaptcha settings #}

```

### Redirecting after submit

[](#redirecting-after-submit)

If you have a ‘redirect’ hidden input, the user will get redirected to it upon successfully sending the email.

Note that if you don’t include a `redirect` input, the current page will get reloaded.

### Displaying flash messages

[](#displaying-flash-messages)

When a contact form is submitted, the plugin will set a `success` flash message on the user session. This is so, you can have a success message after the form has been submitted and can be displayed on redirected page. The available flash variables are: `wheelformSubmittedForm` - ID of submitted form `wheelformSuccess` - message to display You can display it in your template like this:

```
{% if craft.app.session.hasFlash('wheelformSuccess') %}
    {{ craft.app.session.getFlash('wheelformSuccess') }}
{% endif %}
```

### Form Field Type

[](#form-field-type)

You can assign a Field Type to your sections where Users can select which form to display based on a Dropdown. This field will return a `wheelform.form` template service (same as other examples) that belongs to the form selected on the Admin Panel. if you need to customize it you can use the `setConfig` variable to modify the default behaviour.

```
{% set form = entry.formField.setConfig({
    redirect: 'contact/thanks',
    attributes: {
        'novalidate':"novalidate",
        'id':'field-form',
        'class': 'field-form',
    },
}) %}
```

### Displaying the last/current submission

[](#displaying-the-lastcurrent-submission)

Similar to the flash message (will only be available after submission), when a contact form is submitted the plugin will store the values of the submitted form in the session and make it available (once) through the `wheelform.lastSubmission` variable. You can use this in the template (typically in your re-direct page) like this:

```
{% set submission = wheelform.lastSubmission %}
{% if submission %}

        {% for field in submission.fields %}
            {{ field.label }}
            {{ field.value }}
        {% endfor %}

{% endif %}
```

You also have available `submission.id`, `submission.formId` and `submission.date`(Note: `submission.date` is a DateTime object run it through `date()` filter).

### Recaptcha V3

[](#recaptcha-v3)

```
{# You need to add the Recaptcha Init before the form.open() #}
{# action is optional, action defaults to form URL #}
{{ wheelform.recaptchaV3({'action': 'contact-form'})}}
```

### Displaying existing form submissions

[](#displaying-existing-form-submissions)

You can access existing submitted form entries on a form through the `form.entries` property:

```
{% set form = wheelform.form({ id: 1 }) %}

{# form.entries(start, limit) can be used for pagination purposes #}
{% set entries = form.entries %}

{# form.fields returns active form fields #}
{% set fields = form.fields %}

    {% for field in fields %}
        {{ field.label }}
    {% endfor %}
    Date

    {% for entry in entries %}

            {% for field in fields %}
                {% set current = entry.fields[field.name] %}
                {{ current.value }}
            {% endfor %}
            {{ entry.date|date("m/d/Y") }}

    {% endfor %}

```

### Displaying specific Form Submission

[](#displaying-specific-form-submission)

You can access specific form entry by loading the form and requesting it by ID:

```
{% set form = wheelform.form({ id: 1 }) %}
{% set entry = form.entry(id) %}
{% for field in entry.fields %}
    {{ field.value }}
{% endfor %}
```

### File attachments

[](#file-attachments)

If you would like your form to accept file attachments, follow these steps:

1. Make sure your opening HTML `` tag contains `enctype="multipart/form-data"`.
2. Add a `` to your form.

### File saving to asset Folder

[](#file-saving-to-asset-folder)

On Plugin Settings select the Folder you would like to save files. Make sure `Allow public URLs` option is turned on.

### Ajax form submissions

[](#ajax-form-submissions)

You can optionally post contact form submissions over Ajax if you’d like. Just send a POST request to your site with all of the same data that would normally be sent:

**JQuery**

```
$('#my-form').submit(function(ev) {
    // Prevent the form from actually submitting
    ev.preventDefault();

    var data = $(this).serialize();

    // Send it to the server
    $.post('/wheelform/message/send',
        data,
        function(response) {
            if (response.success) {
                //reponse.message is the message saved in the Form Settings
                $('#thanks').fadeIn();
            } else {
                // response.values will contain user submitted values
                // response.errors will be an array containing any validation errors that occurred, indexed by field name
                // e.g. response.error['email'] => ['Email is required', 'Email is invalid']
                alert('An error occurred. Please try again.');
            }
        }
    );
});
```

**Basic Javascript using [Axios](https://github.com/axios/axios) and [Babel](https://babeljs.io/) with [Webpack](https://webpack.js.org/)**

```
import axios from 'axios';

const contactForm = document.getElementById('contact-form');

if (contactForm) {
  contactForm.addEventListener('submit', function(event) {
    /**
     * This prevents the default behaviour of the browser submitting
     * the form so that we can handle things instead.
     */
    event.preventDefault();

    /**
     * This gets the element which the event handler was attached to.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget
     */
    const form = event.currentTarget;

    /**
      * Hidden field named action
      */
    const url = form.action.value;

    /**
     * This takes all the fields in the form and makes their values
     * available through a `FormData` instance.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/API/FormData
     */
    const formData = new FormData(form);

    axios({
      method: 'post',
      url: url,
      responseType: 'json',
      headers: {'X-Requested-With': 'XMLHttpRequest'},
      data: formData,
    })
    .then(function (response) {
      console.log(response);
    })
    .catch(function (error) {
      console.log(error);
    });
  });
}
```

If using getCrsfInput() make sure you are submitting it with the rest of your form.

#### Recaptcha with Ajax

[](#recaptcha-with-ajax)

If implementing Recaptcha with Ajax, keep in mind that it is necessary after each Ajax request to refresh the recaptcha token to avoid an invalid recaptcha validation error (see issue [242](https://github.com/xpertbot/craft-wheelform/issues/242)).

Example using Fetch API:

```
const myRequest = new Request('endpoint.json', {
    method: 'POST', // any allowed Method
    param: value
});
fetch(myRequest)
.then((response) => response.json())
.then((data) => {
    // Use respose `data` here

    // Refresh Recaptcha token
    wheelformProcessRecaptchaCallback()
});
```

### CSRF Meta Tags

[](#csrf-meta-tags)

If submitting Ajax request and need Meta Tags inside `head` element you can use `{{ wheelform.metaTags() }}` to generate the appropriate CSRF values.

### Permissions

[](#permissions)

There are 4 different type of permissions ({Form Name} permissions are repeated per form on your website):

- Create new Form - Allows User / Group to see the "New Form" button and create new forms.
- Edit {Form Name} - Allows User / Group to see the form on the list of forms.
    - {Form Name} Entries - Allows User / Group to view the Entries list.
    - {Form Name} Settings - Allows User / Group to Edit the form settings.

### Form Tools

[](#form-tools)

- CSV Exporter can be based on entry date, under Admin &gt; Utilities &gt; Form Tools.
- Form Fields can be exported as a JSON file.
- Form Fields can be imported from a valid JSON file.

### Delete Messages Cron Job

[](#delete-messages-cron-job)

You can schedule a Cron Job on your server to run daily an check to Delete any old Messages values saved on your database. The cron Job Command is: `php var/www/yourwebsite/craft wheelform/message/purge` where `var\www\yourwebsite\craft` is the path to the craft executable package.

The only configuration needed inside `config\wheelform.php` is:

```
return [
    'purgeMessages' => true, //True / False value to allow Cron Job to go
    'purgeMessagesDays' => 30, //Number of days messages should live in your database
];
```

Note: This action cannot be reverted.

### Custom "From" Address per Form

[](#custom-from-address-per-form)

Change the "From" Address based on each form, this will overwritte the General email set on the form settings.

1. Create `wheelform.php` file inside Craft's configuration folder.
2. Add and `array` with the key `forms` with the `ID` of the form you would like to overwrite as the key followed by an array with the key `from`. Example below:

```
return [
    'forms' => [
        // ID of form
        3 => [
            // This is the email to use for this specific form
            'from' => 'form3@example.com',
        ],
        5 => [
            // This can also be an array with a custom name
            'from' => [
                'form5@example.com' => "Form 5 Custom Name",
            ]
        ]
    ]
];
```

### Custom Email Template

[](#custom-email-template)

Email Templates are Optional. Custom Twig templates can be used using these steps:

1. Create `wheelform.php` file inside Craft's config folder.
2. `wheelform.php` expects an array of configuration settings to be returned. The options are:
    - `template`: default template to use for all emails.
    - `notification`: default notification template overwrite.
    - `forms`: is an array that overwrites any settings specific to the form. The key on each array is the ID of the form to modify. (These settings take priority over anything else) (Note: This `forms` key is the same as above for custom "From" Address)

```
return [
    'template' => '_emails/custom',
    'notification' => [
        'template' => '_emails/notification',
        'subject' => 'Default Notification Subject',
    ],
    'forms' => [
        1 => [
            'template' => '_emails/form1_template',
            'notification' => [
                'template' => '_emails/notification2',
                'subject' => 'Form specific Subject',
            ],
        ],
        3 => [
            'template' => '_emails/form3_template',
        ],
    ],
];
```

3. Inside your templates you will have access to a `fields` array and `notification_message` with the message set on the Form Administration Panel. Example:

```

    Custom Template

    {% for field in fields %}

        {{ field.label }}:
        {% switch field.type %}

            {% case "file" %}
                {# This is an object with file attributes #}
                {{ field.value.name }}

            {% case "checkbox" %}
                {# Array of all choices selected #}
                {{ field.value | join(',')}}
            {% case "list" %}
                {% if field.value %}

                    {% for item in field.value %}
                        {{ item }}
                    {% endfor %}

                {% endif %}

            {% default %}

                {# Text based items #}
                {{ field. value }}

        {% endswitch %}

    {% endfor %}

```

### Skip attaching files to email

[](#skip-attaching-files-to-email)

Inside `wheelform.php` each form can have a flag to skip attaching email:

```
return [
    'forms' => [
        1 => [
            'skip_attachments' => true, // True/False value, leave empty if not needed.
        ],
    ],
];
```

### Honeypot Field

[](#honeypot-field)

Honeypot field is a field that is meant to be left blank by humans. Usually hidden by CSS. [More information](https://stackoverflow.com/questions/36227376/better-honeypot-implementation-form-anti-spam) about Honeypot fields.

If not using `{{ form.close() }}` helper tag make sure you add a text field with the name you used when creating the form. Then, hide it from the user using CSS or Javascript.

#### Render Honeypot (Optional)

[](#render-honeypot-optional)

If you need complete control of how the Honeypot field should behave. You can call `{{ form.honeypot($type, $attributes = [], $returnString = false) }}` where:

- `$type`: can be 1 of 3 types; `text`, `password`, `hidden`.
- `$attributes`: (Optional) an array of options for the field. E.G. `{'autocomplete': 'none', 'class': 'comments-field'}`.
- `$returnString`: (Optional) This will return the field HTML string for further manipulation, instead of template ready entities.

### Events

[](#events)

(Note: this is mostly for developers that know basic PHP and Composer Packages)

`beforeValidate` Event, this allows developers to validate the values and add custom errors. skipping the plugin validation altogether, this happens before the basic plugin vaidation.

`afterValidate` Event, this allows developers to validate the Message and adjust the values and errors, this happens after the basic plugin vaidation, these changes cascade into the other Events and Mailers.

`beforeSave` Event, this allows developers to modify the value Active Records objects before being saved to the database, these changes cascade into the other Events and Mailers.

`beforeSend` Event, this allows developers to modify the fields being sent in an email, this event does not modify the values entered in the database. Only the fields being sent to the client.

`afterSend` Event, Final Values sent to the user email, perfect for Third Party integrations and libraries.

`beforeResponse` Event, event that modifies the response of the submission, good place to add Custom headers, dynamic success messages, or custom data to consume on the frontend.

You can also trigger other custom functionality such as gathering custom field values to add to a Third party service such as a Mailing list.

`beforeSend` and `afterSend` object is as follows: `Event` class properties:

- `form_id` - Current ID of form being submitted, This allows developers some way to check what fields are being sent.
- `subject` - Subject of the currnet form. This can be modified to make it customizable.
- `message` - Associative Array of different fields with the values submitted.
- `from` - Email Address message is being send From.
- `to` - Email Address message is being send To (This can be an array of multiple emails).
- `reply_to` - Email Address message can be Reply To.
- `email_html` - Full HTML String that will be sent in the email. This overwrites other email templates.
- `saveMessage` - Allow the message to be saved on the database (Default: True).
- `sendMessage` - Allow the message to be sent (Default: True).

Example Plugin to handle these events. [wheelformhelper](https://github.com/xpertbot/wheelformhelper)

### Translations

[](#translations)

New translations can be submitted using the format inside the translations folder. (I will keep "es" translations up to date as much as possible, that can be a good starting point for your translations)

###  Health Score

60

—

FairBetter than 99% of packages

Maintenance75

Regular maintenance activity

Popularity43

Moderate usage in the ecosystem

Community29

Small or concentrated contributor base

Maturity81

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 92.2% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~22 days

Recently: every ~114 days

Total

123

Last Release

217d ago

Major Versions

2.7.2 → 3.0.02022-05-04

2.7.3 → 3.2.02024-03-03

3.2.1 → 4.0.02024-05-10

2.7.4 → 3.2.22024-11-28

3.2.2 → 4.0.32024-11-28

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/4000383?v=4)[Roger O](/maintainers/xpertbot)[@xpertbot](https://github.com/xpertbot)

---

Top Contributors

[![xpertbot](https://avatars.githubusercontent.com/u/4000383?v=4)](https://github.com/xpertbot "xpertbot (475 commits)")[![roger-greenleaf](https://avatars.githubusercontent.com/u/86792530?v=4)](https://github.com/roger-greenleaf "roger-greenleaf (12 commits)")[![masiorama](https://avatars.githubusercontent.com/u/731916?v=4)](https://github.com/masiorama "masiorama (4 commits)")[![svale](https://avatars.githubusercontent.com/u/5339180?v=4)](https://github.com/svale "svale (4 commits)")[![Gnative](https://avatars.githubusercontent.com/u/1758875?v=4)](https://github.com/Gnative "Gnative (3 commits)")[![timbertens](https://avatars.githubusercontent.com/u/1016655?v=4)](https://github.com/timbertens "timbertens (2 commits)")[![alexanderbuergin](https://avatars.githubusercontent.com/u/85960512?v=4)](https://github.com/alexanderbuergin "alexanderbuergin (2 commits)")[![AlexFUNBIT](https://avatars.githubusercontent.com/u/10828933?v=4)](https://github.com/AlexFUNBIT "AlexFUNBIT (2 commits)")[![MatoTominac](https://avatars.githubusercontent.com/u/10546885?v=4)](https://github.com/MatoTominac "MatoTominac (1 commits)")[![ncareau](https://avatars.githubusercontent.com/u/2974631?v=4)](https://github.com/ncareau "ncareau (1 commits)")[![popperz0r](https://avatars.githubusercontent.com/u/7389447?v=4)](https://github.com/popperz0r "popperz0r (1 commits)")[![bertheyman](https://avatars.githubusercontent.com/u/5979524?v=4)](https://github.com/bertheyman "bertheyman (1 commits)")[![timvermaercke](https://avatars.githubusercontent.com/u/2750752?v=4)](https://github.com/timvermaercke "timvermaercke (1 commits)")[![vandres](https://avatars.githubusercontent.com/u/1436383?v=4)](https://github.com/vandres "vandres (1 commits)")[![coffeylukas](https://avatars.githubusercontent.com/u/16714057?v=4)](https://github.com/coffeylukas "coffeylukas (1 commits)")[![cbovers](https://avatars.githubusercontent.com/u/29738458?v=4)](https://github.com/cbovers "cbovers (1 commits)")[![ipetrov87](https://avatars.githubusercontent.com/u/14108063?v=4)](https://github.com/ipetrov87 "ipetrov87 (1 commits)")[![jgdevweb](https://avatars.githubusercontent.com/u/32622953?v=4)](https://github.com/jgdevweb "jgdevweb (1 commits)")[![luke-nehemedia](https://avatars.githubusercontent.com/u/7863273?v=4)](https://github.com/luke-nehemedia "luke-nehemedia (1 commits)")

---

Tags

craftcraft-cmscraft-plugincmsCraftcraftcmscraft-pluginWheel FormWheelForm

### Embed Badge

![Health badge](/badges/xpertbot-craft-wheelform/health.svg)

```
[![Health](https://phpackages.com/badges/xpertbot-craft-wheelform/health.svg)](https://phpackages.com/packages/xpertbot-craft-wheelform)
```

###  Alternatives

[nystudio107/craft-seomatic

SEOmatic facilitates modern SEO best practices &amp; implementation for Craft CMS 5. It is a turnkey SEO system that is comprehensive, powerful, and flexible.

1741.4M46](/packages/nystudio107-craft-seomatic)[verbb/image-resizer

Resize assets when they are uploaded.

127269.1k7](/packages/verbb-image-resizer)[verbb/tablemaker

Create customizable and user-defined table fields.

40168.8k1](/packages/verbb-tablemaker)[wrav/oembed

A simple plugin to extract media information from websites, like youtube videos, twitter statuses or blog articles.

36205.0k3](/packages/wrav-oembed)[verbb/hyper

A user-friendly links field for Craft.

24130.9k9](/packages/verbb-hyper)[verbb/social-poster

Automatically post entries to social media.

918.5k](/packages/verbb-social-poster)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
