public override async Task <CatalogProductsModel> PrepareSearchProductsModelAsync(SearchModel searchModel, CatalogProductsCommand command) { if (command == null) { throw new ArgumentNullException(nameof(command)); } var model = new CatalogProductsModel { UseAjaxLoading = _catalogSettings.UseAjaxCatalogProductsLoading }; //sorting await PrepareSortingOptionsAsync(model, command); //view mode await PrepareViewModesAsync(model, command); //page size await PreparePageSizeOptionsAsync(model, command, _catalogSettings.SearchPageAllowCustomersToSelectPageSize, _catalogSettings.SearchPagePageSizeOptions, _catalogSettings.SearchPageProductsPerPage); var searchTerms = searchModel.q == null ? string.Empty : searchModel.q.Trim(); IPagedList <Product> products = new PagedList <Product>(new List <Product>(), 0, 1); // only search if query string search keyword is set (used to aasync Task searching or displaying search term min length error message on /search page load) //we don't use "!string.IsNullOrEmpty(searchTerms)" in cases of "ProductSearchTermMinimumLength" set to 0 but searching by other parameters (e.g. category or price filter) var isSearchTermSpecified = _httpContextAccessor.HttpContext.Request.Query.ContainsKey("q"); if (isSearchTermSpecified) { var currentStore = await _storeContext.GetCurrentStoreAsync(); if (searchTerms.Length < _catalogSettings.ProductSearchTermMinimumLength) { model.WarningMessage = string.Format(await _localizationService.GetResourceAsync("Search.SearchTermMinimumLengthIsNCharacters"), _catalogSettings.ProductSearchTermMinimumLength); } else { var categoryIds = new List <int>(); var manufacturerId = 0; var searchInDescriptions = false; var vendorId = 0; if (searchModel.advs) { //advanced search var categoryId = searchModel.cid; if (categoryId > 0) { categoryIds.Add(categoryId); if (searchModel.isc) { //include subcategories categoryIds.AddRange( await _categoryService.GetChildCategoryIdsAsync(categoryId, currentStore.Id)); } } manufacturerId = searchModel.mid; if (searchModel.asv) { vendorId = searchModel.vid; } searchInDescriptions = searchModel.sid; } //var searchInProductTags = false; var searchInProductTags = searchInDescriptions; var workingLanguage = await _workContext.GetWorkingLanguageAsync(); //price range PriceRangeModel selectedPriceRange = null; if (_catalogSettings.EnablePriceRangeFiltering && _catalogSettings.SearchPagePriceRangeFiltering) { selectedPriceRange = await GetConvertedPriceRangeAsync(command); PriceRangeModel availablePriceRange = null; if (!_catalogSettings.SearchPageManuallyPriceRange) { async Task <decimal?> getProductPriceAsync(ProductSortingEnum orderBy) { var products = await _productService.SearchProductsAsync(0, 1, categoryIds : categoryIds, manufacturerIds : new List <int> { manufacturerId }, storeId : currentStore.Id, visibleIndividuallyOnly : true, keywords : searchTerms, searchDescriptions : searchInDescriptions, searchProductTags : searchInProductTags, languageId : workingLanguage.Id, vendorId : vendorId, orderBy : orderBy); return(products?.FirstOrDefault()?.Price ?? 0); } availablePriceRange = new PriceRangeModel { From = await getProductPriceAsync(ProductSortingEnum.PriceAsc), To = await getProductPriceAsync(ProductSortingEnum.PriceDesc) }; } else { availablePriceRange = new PriceRangeModel { From = _catalogSettings.SearchPagePriceFrom, To = _catalogSettings.SearchPagePriceTo }; } model.PriceRangeFilter = await PreparePriceRangeFilterAsync(selectedPriceRange, availablePriceRange); } //products if (_luceneSettings.Enabled) { _luceneService.GetLuceneDirectory(); var luceneProducts = _luceneService.Search(searchTerms); products = await luceneProducts.AsQueryable().ToPagedListAsync(command.PageNumber - 1, command.PageSize); } else { products = await _productService.SearchProductsAsync( command.PageNumber - 1, command.PageSize, categoryIds : categoryIds, manufacturerIds : new List <int> { manufacturerId }, storeId : currentStore.Id, visibleIndividuallyOnly : true, keywords : searchTerms, priceMin : selectedPriceRange?.From, priceMax : selectedPriceRange?.To, searchDescriptions : searchInDescriptions, searchProductTags : searchInProductTags, languageId : workingLanguage.Id, orderBy : (ProductSortingEnum)command.OrderBy, vendorId : vendorId); } //search term statistics if (!string.IsNullOrEmpty(searchTerms)) { var searchTerm = await _searchTermService.GetSearchTermByKeywordAsync(searchTerms, currentStore.Id); if (searchTerm != null) { searchTerm.Count++; await _searchTermService.UpdateSearchTermAsync(searchTerm); } else { searchTerm = new SearchTerm { Keyword = searchTerms, StoreId = currentStore.Id, Count = 1 }; await _searchTermService.InsertSearchTermAsync(searchTerm); } } //event await _eventPublisher.PublishAsync(new ProductSearchEvent { SearchTerm = searchTerms, SearchInDescriptions = searchInDescriptions, CategoryIds = categoryIds, ManufacturerId = manufacturerId, WorkingLanguageId = workingLanguage.Id, VendorId = vendorId }); } } var isFiltering = !string.IsNullOrEmpty(searchTerms); await PrepareCatalogProductsAsync(model, products, isFiltering); return(model); }