Filters
Introduction
Filters in Botble CMS are hooks that allow you to modify data during the execution of the application. Unlike actions, which simply execute code at specific points, filters are designed to transform data and return a modified version.
Filters are used throughout Botble CMS to allow plugins and themes to modify content, settings, and other data without changing core files. They provide a powerful way to customize the behavior of the CMS in a modular and maintainable way.
Using Filters
Adding a Filter
To hook into a filter, use the add_filter()
function:
add_filter(string|array $tag, callable $callback, int $priority = 20, int $accepted_args = 1)
Parameters
- $tag: (string|array) The name of the filter(s) to hook into. Can be a single filter name or an array of filter names.
- $callback: (callable) The function or method to be called when the filter is applied.
- $priority: (int) Optional. Used to specify the order in which callbacks are executed. Lower numbers = earlier execution. Default is 20.
- $accepted_args: (int) Optional. The number of arguments your callback accepts. Default is 1.
Example
// In a service provider's boot method or theme functions.php
add_filter('base_filter_public_single_data', function ($data, $model) {
if ($model instanceof \Botble\Blog\Models\Post) {
// Modify post data
$data['custom_field'] = get_meta_data($model, 'custom_field', true);
}
return $data;
}, 20, 2);
Applying a Filter
To apply a filter (usually done in core code), use the apply_filters()
function:
$modified_value = apply_filters(string $tag, mixed $value, ...$args)
Parameters
- $tag: (string) The name of the filter to apply.
- $value: (mixed) The value to filter.
- $args: (mixed) Optional. Additional arguments to pass to the callbacks hooked to the filter.
Example
// In a controller or service
public function getData($id)
{
$post = Post::findOrFail($id);
$data = $post->toArray();
// Apply a filter to the data
$data = apply_filters('blog_post_data', $data, $post);
return $data;
}
Removing a Filter
To remove a previously added filter, use the remove_filter()
function:
remove_filter(string $tag)
Example
// Remove all callbacks for a filter
remove_filter('base_filter_public_single_data');
Common Filter Hooks
Botble CMS provides many filter hooks that you can use in your plugins and themes. Here are some of the most commonly used ones:
Content Filters
BASE_FILTER_PUBLIC_SINGLE_DATA: Modify data for a single item on the front end.
phpadd_filter(BASE_FILTER_PUBLIC_SINGLE_DATA, function ($data, $model) { // Modify single item data return $data; }, 20, 2);
BASE_FILTER_BEFORE_GET_SINGLE: Modify query before getting a single item.
phpadd_filter(BASE_FILTER_BEFORE_GET_SINGLE, function ($query, $model) { // Modify query return $query; }, 20, 2);
BASE_FILTER_BEFORE_GET_BY_SLUG: Modify query before getting an item by slug.
phpadd_filter(BASE_FILTER_BEFORE_GET_BY_SLUG, function ($query, $model, $slug) { // Modify query return $query; }, 20, 3);
Form Filters
BASE_FILTER_BEFORE_RENDER_FORM: Modify form before rendering.
phpadd_filter(BASE_FILTER_BEFORE_RENDER_FORM, function ($form, $data) { // Modify form return $form; }, 20, 2);
BASE_FILTER_AFTER_FORM_CREATED: Modify form after creation.
phpadd_filter(BASE_FILTER_AFTER_FORM_CREATED, function ($form, $data) { // Modify form return $form; }, 20, 2);
BASE_FILTER_FORM_EDITOR_BUTTONS: Modify editor buttons.
phpadd_filter(BASE_FILTER_FORM_EDITOR_BUTTONS, function ($buttons) { // Add or remove buttons $buttons[] = 'myCustomButton'; return $buttons; }, 20, 1);
Dashboard Filters
DASHBOARD_FILTER_ADMIN_LIST: Modify dashboard widgets.
phpadd_filter(DASHBOARD_FILTER_ADMIN_LIST, function ($widgets, $widgetSettings) { // Add or modify dashboard widgets return $widgets; }, 20, 2);
DASHBOARD_FILTER_ADMIN_NOTIFICATIONS: Modify dashboard notifications.
phpadd_filter(DASHBOARD_FILTER_ADMIN_NOTIFICATIONS, function ($notifications) { // Add or modify notifications return $notifications . '<div class="alert alert-info">Custom notification</div>'; }, 20, 1);
Table Filters
BASE_FILTER_TABLE_HEADINGS: Modify table headings.
phpadd_filter(BASE_FILTER_TABLE_HEADINGS, function ($headings, $table) { // Modify table headings return $headings; }, 20, 2);
BASE_FILTER_TABLE_BUTTONS: Modify table buttons.
phpadd_filter(BASE_FILTER_TABLE_BUTTONS, function ($buttons, $table) { // Add or modify table buttons return $buttons; }, 20, 2);
BASE_FILTER_GET_LIST_DATA: Modify data for tables.
phpadd_filter(BASE_FILTER_GET_LIST_DATA, function ($data, $model) { // Modify list data return $data; }, 20, 2);
Menu Filters
BASE_FILTER_DASHBOARD_MENU: Modify dashboard menu.
phpadd_filter(BASE_FILTER_DASHBOARD_MENU, function ($menu) { // Modify dashboard menu return $menu; }, 20, 1);
BASE_FILTER_APPEND_MENU_NAME: Append text to menu names.
phpadd_filter(BASE_FILTER_APPEND_MENU_NAME, function ($name, $menuId) { // Append text to menu name if ($menuId === 'cms-plugins-blog') { return $name . ' <span class="badge badge-success">New</span>'; } return $name; }, 20, 2);
Enum Filters
BASE_FILTER_ENUM_ARRAY: Modify enum values.
phpadd_filter(BASE_FILTER_ENUM_ARRAY, function ($values, $class) { if ($class === \Botble\Base\Enums\BaseStatusEnum::class) { $values['PENDING'] = 'pending'; } return $values; }, 20, 2);
BASE_FILTER_ENUM_LABEL: Modify enum labels.
phpadd_filter(BASE_FILTER_ENUM_LABEL, function ($label, $class, $value) { if ($class === \Botble\Base\Enums\BaseStatusEnum::class && $value === 'pending') { return 'Waiting for approval'; } return $label; }, 20, 3);
Best Practices
Always Return a Value: Filters must always return a value, even if you don't modify it.
Use Appropriate Priority: Choose a priority that makes sense for your filter. Lower numbers run earlier.
Accept Only Needed Arguments: Only specify the number of arguments your callback actually needs.
Check Types: Always check the type of data you're filtering to avoid errors.
Document Your Filters: If you're creating new filter hooks, document them clearly for other developers.
Use Service Providers: Register your filter hooks in service providers' boot methods for better organization.
Creating Custom Filter Hooks
You can create your own filter hooks in your plugins or themes:
// In your controller or service
public function getData($id)
{
$data = YourModel::findOrFail($id)->toArray();
// Apply a custom filter
$data = apply_filters('my_plugin_get_data', $data, $id);
return $data;
}
Other developers can then hook into your custom filter:
add_filter('my_plugin_get_data', function ($data, $id) {
// Modify the data
$data['custom_field'] = 'Custom value';
return $data;
}, 20, 2);
Request Class Filters
Botble CMS provides several filters in the Botble\Support\Http\Requests\Request
class that allow you to modify validation rules, messages, attributes, and data before validation occurs. These filters are particularly useful for plugins that need to extend or modify form validation behavior without modifying core files.
Available Request Filters
core_request_rules: Modify validation rules.
phpadd_filter('core_request_rules', function ($rules, $request) { // Add or modify validation rules if ($request instanceof \Botble\Blog\Http\Requests\PostRequest) { $rules['title'] = 'required|max:255|min:10'; $rules['custom_field'] = 'required|string'; } return $rules; }, 20, 2);
core_request_messages: Modify validation error messages.
phpadd_filter('core_request_messages', function ($messages, $request) { // Add or modify validation messages if ($request instanceof \Botble\Blog\Http\Requests\PostRequest) { $messages['title.min'] = 'The title must be at least 10 characters.'; $messages['custom_field.required'] = 'The custom field is required.'; } return $messages; }, 20, 2);
core_request_attributes: Modify attribute names used in validation messages.
phpadd_filter('core_request_attributes', function ($attributes, $request) { // Add or modify attribute names if ($request instanceof \Botble\Blog\Http\Requests\PostRequest) { $attributes['custom_field'] = 'Custom Field'; } return $attributes; }, 20, 2);
core_request_validation_data: Modify the data to be validated.
phpadd_filter('core_request_validation_data', function ($data, $request) { // Modify the data before validation if ($request instanceof \Botble\Blog\Http\Requests\PostRequest) { // Sanitize or transform input data if (isset($data['title'])) { $data['title'] = trim($data['title']); } // Add computed fields $data['slug'] = \Str::slug($data['title']); } return $data; }, 20, 2);
How It Works
These filters are applied in the createDefaultValidator
method of the Request
class:
protected function createDefaultValidator(ValidationFactory $factory)
{
$rules = method_exists($this, 'rules') ? $this->container->call([$this, 'rules']) : [];
$rules = apply_filters('core_request_rules', $rules, $this);
$messages = apply_filters('core_request_messages', $this->messages(), $this);
$attributes = apply_filters('core_request_attributes', $this->attributes(), $this);
$validationData = apply_filters('core_request_validation_data', $this->validationData(), $this);
// @phpstan-ignore-next-line
$validator = $factory->make(
$validationData,
$rules,
$messages,
$attributes
)->stopOnFirstFailure($this->stopOnFirstFailure);
if ($this->isPrecognitive()) {
$validator->setRules(
$this->filterPrecognitiveRules($validator->getRulesWithoutPlaceholders())
);
}
return $validator;
}
Use Cases
Adding Custom Validation Rules: Add new validation rules to specific request types without modifying the original request classes.
Modifying Validation Messages: Customize error messages for specific fields or rules.
Data Transformation: Transform or sanitize input data before validation occurs.
Dynamic Validation: Add or remove validation rules based on runtime conditions.
Plugin Integration: Allow plugins to extend validation for core features.
Example: Adding Custom Validation to a Post Request
// In a service provider's boot method
public function boot()
{
// Add SEO validation rules to Post requests
add_filter('core_request_rules', function ($rules, $request) {
if ($request instanceof \Botble\Blog\Http\Requests\PostRequest) {
$rules['seo_title'] = 'nullable|string|max:60';
$rules['seo_description'] = 'nullable|string|max:160';
}
return $rules;
}, 20, 2);
// Add custom validation messages
add_filter('core_request_messages', function ($messages, $request) {
if ($request instanceof \Botble\Blog\Http\Requests\PostRequest) {
$messages['seo_title.max'] = 'SEO title should not exceed 60 characters for optimal display in search results.';
$messages['seo_description.max'] = 'SEO description should not exceed 160 characters for optimal display in search results.';
}
return $messages;
}, 20, 2);
// Add custom attribute names
add_filter('core_request_attributes', function ($attributes, $request) {
if ($request instanceof \Botble\Blog\Http\Requests\PostRequest) {
$attributes['seo_title'] = 'SEO Title';
$attributes['seo_description'] = 'SEO Description';
}
return $attributes;
}, 20, 2);
}