I have already wrote how to implement paging toolbar with filtering feature. Here I will show how to implement filter in form of plugin to use it with any toolbar of the grid.

Of course your toolbar can already have other GUI elements so I have implemented it with support of the placeholders. In the following sample I have a grid reload button and two filter elements: menu button and filter text field will be place after it in between delimiters.

initComponent: function () {
        this.items = [
            this.getReloadButton(),
            '-',
            '**FILTER_SPLIT_BUTTON**',
            '**FILTER_TEXT_FIELD**',
            '-'
        ];
        this.callParent();
    },

And I am not forgetting the initialization of the plugin:

plugins: {
        filterplugin: {

        }
    }

The plugin code:

Ext.define('App.ux.grid.toolbar.plugin.Filter', {
    extend: 'Ext.plugin.Abstract',
    alias: 'plugin.filterplugin',

    filterItemWidth: 100,
    filterOnType: true,
    filterSplitButtonGlyph: 'xf0b0@FontAwesome',
    filterSplitButtonText: "Filter",

    filterSplitButtonPlaceHolder: '**FILTER_SPLIT_BUTTON**',
    filterTextFieldPlaceHolder: '**FILTER_TEXT_FIELD**',

    init: function (toolbar) {
        this.placeFields();
        toolbar.on('afterrender', this.updateSearchColumnsMenu, this);
    },

    placeFields: function () {
        this.replacePlaceHolderByCmp(
            this.filterSplitButtonPlaceHolder,
            this.getFilterSplitButton()
        );
        this.replacePlaceHolderByCmp(
            this.filterTextFieldPlaceHolder,
            this.getFilterTextField()
        );
    },

    replacePlaceHolderByCmp: function (placeHolder, cmp) {
        var placeHolderIndex = this.getIndexByPlaceHolder(placeHolder),
            placeHolderCmp = this.getPlaceHolderCmp(placeHolder);
        this.getCmp().remove(placeHolderCmp);
        this.getCmp().insert(placeHolderIndex, cmp);
    },

    getIndexByPlaceHolder: function (placeHolder) {
        return this.getCmp().items.findIndex('text', placeHolder);
    },

    getPlaceHolderCmp: function (placeHolder) {
        var cmp = this.getCmp().down('[text="' + placeHolder + '"]');
        return cmp;
    },

    getFilterSplitButton: function () {
        if (!this.filterSplitButton) {
            this.filterSplitButton = Ext.create('Ext.button.Split', {
                text: this.filterSplitButtonText,
                handler: this.doFilter,
                glyph: this.filterSplitButtonGlyph,
                scope: this
            });
        }
        return this.filterSplitButton;
    },

    getFilterTextField: function () {
        if (!this.filterTextField) {
            this.filterTextField = Ext.create('Ext.form.field.Text', {
                submitValue: false,
                isFormField: false,
                width: this.filterItemWidth,
                margin: '-1 2 3 2',
                enableKeyEvents: true
            });
            if (this.filterOnType) {
                this.filterTextField.on('change', this.doFilter, this);
            } else {
                this.filterTextField.on('specialkey', function () {
                    if (e.getKey() == e.ENTER) {
                        this.doFilter();
                    }
                }, this);
            }
        }
        return this.filterTextField;
    },

    getSelectAllColumnsMenuItem: function () {
        if (!this.selectAllColumnsMenuItem) {
            this.selectAllColumnsMenuItem = Ext.create('Ext.menu.CheckItem', {
                text: "All Columns",
                checked: true,
                listeners: {
                    checkchange: {
                        fn: function (menuCheckItem, checked) {
                            this.getFilterColumnsMenu().items.each(function (item) {
                                if (item.dataIndex) {
                                    item.setChecked(checked);
                                }
                            });
                            this.doFilter();
                        },
                        scope: this
                    }
                }
            });
        }
        return this.selectAllColumnsMenuItem;
    },

    getFilterColumnsMenu: function () {
        if (!this.filterColumnsMenu) {
            this.filterColumnsMenu = Ext.create('Ext.menu.Menu', {
                items: [
                    this.getSelectAllColumnsMenuItem(), {
                        xtype: 'menuseparator'
                    }
                ]
            });
        }
        return this.filterColumnsMenu;
    },

    updateSearchColumnsMenu: function () {
        var columns = this.getCmp().up('grid').getColumns();
        Ext.Array.each(columns, function (column) {
            this.getFilterColumnsMenu().add({
                xtype: 'menucheckitem',
                text: column.text,
                dataIndex: column.dataIndex,
                checked: true,
                listeners: {
                    checkchange: {
                        fn: function (menuCheckItem, checked) {
                            if (checked) {
                                var selectAllColumnsMenuItemCheck = true;
                                this.getFilterColumnsMenu().items.each(function (item) {
                                    if (item.dataIndex && item.checked == false) {
                                        selectAllColumnsMenuItemCheck = false;
                                        return false;
                                    }
                                });
                                this.getSelectAllColumnsMenuItem().setChecked(selectAllColumnsMenuItemCheck, true);
                            } else {
                                this.getSelectAllColumnsMenuItem().setChecked(false, true);
                            }
                            this.doFilter();
                        },
                        scope: this
                    }
                }
            });
        }, this);
        this.getFilterSplitButton().setMenu(this.getFilterColumnsMenu());
    },

    doFilter: function () {
        var searchColumnIndexes = [],
            searchValue = this.getFilterTextField().getValue();;

        this.getFilterSplitButton().getMenu().items.each(function (item) {
            if (item.dataIndex && item.checked) {
                searchColumnIndexes.push(item.dataIndex);
            }
        }, this);

        if (this.getStore().remoteFilter) {
            this.remoteFilter(searchColumnIndexes, searchValue)
        } else {
            this.localFilter(searchColumnIndexes, searchValue);
        }

    },

    localFilter: function (searchColumnIndexes, searchValue) {
        this.getStore().removeFilter(this.filter);
        this.filter = new Ext.util.Filter({
            filterFn: function (record) {
                if (searchColumnIndexes.length === 0 || Ext.isEmpty(searchValue)) {
                    return true;
                }

                var found = false;
                Ext.Array.each(searchColumnIndexes, function (dataIndex) {
                    if (record.get(dataIndex) && record.get(dataIndex).indexOf(searchValue) != -1) {
                        found = true;
                        return false;
                    }
                }, this);
                return found;
            }
        });
        this.getStore().addFilter(this.filter);
    },

    remoteFilter: function (searchColumnIndexes, searchValue) {
        var remoteFilters = [];
        Ext.Array.each(searchColumnIndexes, function (columnIndex) {
            remoteFilters.push({
                property: columnIndex,
                value: searchValue
            });
        });
        this.getStore().clearFilter();
        this.getStore().filter(remoteFilters);
    },

    getStore: function () {
        if (!this.store) {
            this.store = this.getCmp().up('grid').getStore();
        }
        return this.store;
    }

});