In Yii applications, different types of users may need different layouts. For example, administrators may use an admin dashboard layout, while regular users can continue using the standard website layout.
Yii allows you to change the controller layout dynamically based on the currently logged-in user's role. A clean way to handle this in Yii 1.x is to create a custom filter and apply it through the controller.
Why Use Different Layouts for Different User Roles?
Role-based layouts are useful when an application has separate interfaces for administrators, customers, employees, or other user types.
- Administrators: Can use a dashboard-style layout with navigation and management tools.
- Regular users: Can use the normal website layout.
- Employees or staff: Can have a dedicated application interface.
- Special user roles: Can receive layouts designed for their specific workflow.
Instead of adding layout-selection logic separately to every controller action, you can centralize it in a filter.
How to Switch Yii Layout Based on User Role
The following example uses Yii 1.x and assumes that your application already has a user role system.
1. Create LayoutFilter.php
Create a new file named LayoutFilter.php inside your application's protected/components/ directory.
<?phpclass LayoutFilter extends CFilter{ protected function preFilter($filterChain) { // Get the roles assigned to the current user $roles = Yii::app()->user->getState('roles'); if (!is_array($roles)) { $roles = array(); } // Use the admin layout for administrators if (in_array(User::ROLE_ADMIN, $roles)) { $filterChain->controller->layout = 'admin/column2'; } else { // Use the default layout for other users $filterChain->controller->layout = '//layouts/column2'; } return parent::preFilter($filterChain); } protected function postFilter($filterChain) { // Logic can be added here after the action is executed return parent::postFilter($filterChain); }}
The preFilter() method runs before the controller action. It checks the current user's roles and assigns the appropriate layout before the page is rendered.
2. Understand the Layout Paths
In the example above, administrators use:
admin/column2
While other users use:
//layouts/column2
Make sure these layout files actually exist in your application.
For example, your application may have a structure similar to:
protected/├── components/│ ├── Controller.php│ └── LayoutFilter.php├── controllers/├── views/│ ├── layouts/│ │ └── column2.php│ └── admin/│ └── column2.php
The exact directory structure can vary depending on how your Yii application is organized.
3. Register the Layout Filter in Controller.php
Open:
protected/components/Controller.php
Add the custom filter to the controller's filters() method:
public function filters(){ return array( 'rights', array('application.components.LayoutFilter'), );}
This makes the LayoutFilter available to controllers that inherit from the base Controller class.
4. Keep Controller Filters Inherited
If individual controllers define their own filters() method, make sure they inherit the filters from the parent controller.
For example:
public function filters(){ return parent::filters() + array( 'postOnly + delete', );}
The parent::filters() call is important because it preserves filters defined in the base controller, including your LayoutFilter.
The postOnly + delete filter also ensures that the delete action can only be accessed through a POST request.
How the Code Works
The process is straightforward:
- A user accesses a controller action.
- Yii executes the configured filters before the action.
LayoutFilterretrieves the user's stored roles.- The filter checks whether the user has
User::ROLE_ADMIN. - If the user is an administrator, Yii selects the admin layout.
- Otherwise, Yii uses the standard layout.
- The controller action continues normally.
Example: Supporting Multiple Roles
If your application has more than one role, you can extend the filter to assign different layouts.
protected function preFilter($filterChain){ $roles = Yii::app()->user->getState('roles'); if (!is_array($roles)) { $roles = array(); } if (in_array(User::ROLE_ADMIN, $roles)) { $filterChain->controller->layout = 'admin/column2'; } elseif (in_array(User::ROLE_MANAGER, $roles)) { $filterChain->controller->layout = 'manager/column2'; } else { $filterChain->controller->layout = '//layouts/column2'; } return parent::preFilter($filterChain);}
This approach allows you to create a different interface for each major user role without duplicating the layout-selection code across controllers.
Important: Layout Selection Is Not Access Control
Changing a layout based on a user's role only changes the presentation of the page. It does not prevent a user from accessing an action.
For example, assigning an admin layout does not automatically make an action accessible only to administrators. Authorization should be handled separately using Yii's access-control or authorization mechanisms.
In other words:
- Layout: Controls how the page is displayed.
- Authorization: Controls what the user is allowed to access.
This separation is important for application security.
Common Problems and How to Fix Them
Layout Is Not Changing
Check that the filter is registered correctly and that the controller inherits from your base Controller class.
Also verify that the layout path is correct and that the corresponding layout file exists.
User Roles Are Empty
If Yii::app()->user->getState('roles') returns an empty value, verify that the roles are actually stored in the user's session state after authentication.
You can temporarily inspect the value while debugging:
var_dump(Yii::app()->user->getState('roles'));
Remove debugging output after testing.
Custom Filter Is Not Executing
Check the filter configuration:
array('application.components.LayoutFilter')
Also make sure the file is named exactly:
LayoutFilter.php
and the class name matches:
class LayoutFilter extends CFilter
Child Controller Overrides the Filters
A common issue is defining filters() in a child controller without calling parent::filters().
For example, this can prevent the inherited filters from being applied:
public function filters(){ return array( 'postOnly + delete', );}
Instead, preserve the parent filters:
public function filters(){ return parent::filters() + array( 'postOnly + delete', );}
Best Practices
- Keep role-based layout logic in one reusable filter instead of duplicating it in every controller.
- Use constants such as
User::ROLE_ADMINinstead of hard-coded role strings. - Make sure every configured layout file exists.
- Keep layout selection separate from authorization and access control.
- Preserve parent filters when overriding
filters()in child controllers. - Test the application with each supported user role.
- Do not expose administrative functionality simply because an admin layout is being displayed.
Conclusion
Using a custom Yii filter is a practical way to switch layouts according to the current user's role. It keeps the logic centralized, reduces duplication, and makes it easier to maintain different interfaces for administrators and regular users.
The key idea is to determine the user's role in preFilter(), assign the appropriate controller layout, and allow the requested action to continue normally.
Frequently Asked Questions
1. Can I use different layouts for different Yii user roles?
Yes. You can check the current user's role and assign a different layout to the controller using a custom filter.
2. Where should I create the LayoutFilter class?
For a typical Yii 1.x application, you can create LayoutFilter.php inside the protected/components/ directory.
3. Does changing the layout restrict access to a page?
No. A layout only controls the presentation of a page. You should use Yii's authorization or access-control mechanisms to restrict access to protected actions.
4. Why should I use a filter instead of changing the layout in every controller?
A filter centralizes the logic. This avoids repeating the same role-checking code across multiple controllers and makes future changes easier.
5. Can I have separate layouts for admin, manager, and normal users?
Yes. You can check multiple roles and assign a specific layout to each role.
6. What happens if the user has no roles?
In the example, the roles value is converted to an empty array when it is not an array. The user will therefore receive the default layout.
7. Why do I need parent::filters() in child controllers?
If a child controller overrides filters() without calling parent::filters(), filters configured in the parent controller may not be included. Calling the parent method preserves those filters.
8. Can I change the layout dynamically without creating a custom filter?
Yes. You can set $this->layout directly inside a controller. However, a custom filter is useful when the same role-based layout logic needs to be applied across multiple controllers.
9. What is the difference between admin/column2 and //layouts/column2?
They represent different Yii layout paths. The exact location depends on your application's view and layout structure. Make sure the corresponding PHP layout files exist.
10. Does this approach work with Yii 2?
No. This example is written for Yii 1.x because it uses classes and patterns such as CFilter and Yii::app(). Yii 2 uses a different architecture and filter system, so the implementation needs to be adapted.
Last updated: