I have a site that uses Wayfinder to display the latest 3 entries from an Articles blog. Now, I want to only consider those blog entries that are tagged Highlights.
My original Wayfinder call looks like this, nothing spectacular:
[[!Wayfinder? &startId=`296` &level=`1`
&outerTpl=`emptyTpl`
&innerTpl=``
&rowTpl=`thumbnails_formatter`
&ignoreHidden=`1`
&sortBy=`menuindex`
&sortOrder=`DESC`
&limit=`3`
&cacheResults=`0`
]]
as Articles tags are managed via the articlestags TV, I thought that a &where might do the trick, but with no luck yet:
&where=`[{"articlestags:LIKE":"%Highlights%"}]`
does not yield anything. As a sanity check, I tried [{"pagetitle:LIKE":"%something%"}], which worked. Obviously, the problem is that articlestags is not a column of modx_site_content, but I'm not sure about how to put the subquery.
SELECT contentid
FROM modx_site_tmplvar_contentvalues
WHERE tmplvarid=17
AND value LIKE '%Highlights%'
Gave me the right IDs on the sql prompt, but adding it to the Wayfinder call like this gave an empty result again:
&where=`["id IN (SELECT contentid FROM modx_site_tmplvar_contentvalues WHERE tmplvarid=17 AND value LIKE '%Highlights%')"]`
Any ideas on how to achieve this? I'd like to stay with Wayfinder for consistency, but other solutions are welcome as well.
You can just use pdomenu (part of pdoTools) instead Wayfinder
[[!PdoMenu?
&startId=`296`
&level=`1`
&outerTpl=`emptyTpl`
&innerTpl=``
&rowTpl=`thumbnails_formatter`
&ignoreHidden=`1`
&sortBy=`menuindex`
&sortOrder=`DESC`
&limit=`3`
&cacheResults=`0`
&includeTVs=`articlestags`
&where=`[{"TVarticlestags.value:LIKE":"%filter%"}]`
]]
Take a peek at some of the config files [core/components/wayfinder/configs ] - I have not tried it, but it looks as if you can run your select query right in the config & pass the tmplvarid array to the $where variable.
A little playing around led me to a solution: I needed to include the class name (not table name) when referring to the ID:
&where=`["modResource.id IN (SELECT contentid FROM modx_site_tmplvar_contentvalues WHERE tmplvarid=17 AND value LIKE '%Highlights%')"]`
a small test showed that even a simple
&where=`["id = 123"]`
does not work without modResource..
A look at wayfinder.class.php shows the following line, which seems to be the "culprit":
$c->select($this->modx->getSelectColumns('modResource','modResource'));
This method aliases the selected columns - relevant code is in xpdoobject.class.php. The first parameter is the class name, the second a table alias. The effect is that the query selects id AS modResource.id, and so on.
EDIT: final version of my query:
&where=`["modResource.id IN (
SELECT val.contentid
FROM modx_site_tmplvars AS tv
JOIN modx_site_tmplvar_contentvalues AS val
ON tv.id = val.tmplvarid
WHERE tv.name = 'articlestags' AND (
val.value = 'Highlights'
OR val.value LIKE 'Highlights,%'
OR val.value LIKE '%,Highlights'
OR val.value LIKE '%,Highlights,%'
)
)"]`
I don't claim this query is particularly efficient (I seem to recall that OR conditions are bad). Also, MODx won't work with this one if the newlines aren't stripped out. Still, I prefer to publish the query in its well-formatted form.
I used snippet as a parameter for the includeDocs of wayfinder, In my case it was useful because I was need different resources in menu depend on user browser (mobile or desktop)
[[!Wayfinder?
&startId=`4`
&level=`1`
&includeDocs=`[[!menu_docs?&startId=`4`]]`
&outerTpl=`home_menu_outer`
&rowTpl=`menu_row`
]]
and then menu_docs snippet
<?php
if (empty ($startId))
return;
if (!isMobileDevice())
return;
$query = $modx->newQuery('modResource');
$query->innerJoin('modTemplateVarResource','TemplateVarResources');
$query->where(array(
'TemplateVarResources.tmplvarid' => 3,
'TemplateVarResources.value:LIKE' => 'yes',
'modResource.parent' => $startId,
'modResource.deleted' => 0,
'modResource.published' => 1,
'modResource.hidemenu' => 0
));
$resources = $modx->getCollection('modResource', $query);
$ouput = array();
foreach ($resources as $resource)
$output[] = $resource->get('id');
return implode (',', $output);
I'm using the search portlet in certain areas of my website, but I'd like to restrict the results to only search for a specific content type: for example only search the news items, or only show Faculty Staff Directory profiles.
I know you can do this after you get to the ##search form through that "filter" list, but is there a way to start with the filter on, so that the "Live Search" results only show the relevant results (i.e. only news items or only profiles).
I suspect you know it already, but just to be sure: You can globally define which types should be allowed to show up in searchresults in the navigations-settings of the controlpanel, and then export and include the relevant parts to your product's GS-profile-propertiestool.xml.
However, if you would like to have some types excluded only in certain sections, you can customize Products.CMFPlone/skins/plone_scripts/livesearch_reply, which already filters the types, to only show "friendly_types" around line 38 (version 4.3.1) and add a condition like this:
Edit:
I removed the solution to check for the absolute_url of the context, because the context is actually the livesearch_reply in this case, not the current section-location. Instead the statement checks now, if the referer is our section:
REQUEST = context.REQUEST
current_location = REQUEST['HTTP_REFERER']
location_to_filter = '/fullpath/relative/to/siteroot/sectionId'
url_to_filter = str(portal_url) + location_to_filter
types_to_filter = ['Event', 'News Item']
if current_location.find(url_to_filter) != -1 or current_location.endswith(url_to_filter):
friendly_types = types_to_filter
else:
friendly_types = ploneUtils.getUserFriendlyTypes()
Yet, this leaves the case open, if the user hits the Return- or Enter-key or the 'Advanced search...'-link, landing on a different result-page than the liveresults have.
Update:
An opportunity to apply the filtering to the ##search-template can be to register a Javascript with the following content:
(function($) {
$(document).ready(function() {
// Let's see, if we are coming from our special section:
if (document.referrer.indexOf('/fullpath/relative/to/siteroot/sectionId') != -1) {
// Yes, we have the button to toggle portal_type-filter:
if ($('#pt_toggle').length>0) {
// If it's checked we uncheck it:
if ($('#pt_toggle').is(':checked')) {
$('#pt_toggle').click();
}
// If for any reason it's not checked, we check and uncheck it,
// which results in NO types to filter, for now:
else {
$('#pt_toggle').click();
$('#pt_toggle').click();
}
// Then we check types we want to filter:
$("input[value='Event']").click();
$("input[value='News Item']").click();
}
}
})
})(jQuery);
Also, the different user-actions result in different, inconsistent behaviours:
Livesearch accepts terms which are not sharp, whereas the ##search-view only accepts sharp terms or requires the user to know, that you can append an asterix for unsharp results.
When hitting the Enter/Return-key in the livesearch-input, the searchterm will be transmitted to the landing-page's (##search) input-element, whilst when clicking on 'Advanced search...' the searchterm gets lost.
Update:
To overcome the sharp results, you can add this to the JS right after the if-statement:
// Get search-term and add an asterix for blurry results:
var searchterm = decodeURI(window.location.search.replace(new RegExp("^(?:.*[&\\?]" + encodeURI('SearchableText').replace(/[\.\+\*]/g, "\\$&") + "(?:\\=([^&]*))?)?.*$", "i"), "$1")) + '*';
// Insert new searchterm in input-text-field:
$('input[name=SearchableText]').val(searchterm);
Update2:
In this related quest, Eric Brehault provides a better solution for passing the asterix during submit: Customize Plone search
Of course you can also customize the target of advanced-search-link in livesearch_reply, respectively in the JS for ##search, yet this link is rather superfluous UI-wise, imho.
Also, if you're still with Archetypes and have more use-cases for pre-filtered searchresults depending on the context, I can recommend to have a look at collective.formcriteria, which allows to define search-criteria via the UI. I love it for it's generic and straightforward plone-ish approach: catalogued indizi and collections. In contradiction to eea.facetednavigation it doesn't break accessibility and can be enhanced progressively with some live-search-js-magic with a little bit of effort, too. Kudos to Ross Patterson here! Simply turn a collection (old-style) into a searchform by changing it's view and it can be displayed as a collection-portlet, as well. And you can decide which criteria the user should be able to change or not (f.e. you hide the type-filter and offer a textsearch-input).
Watch how the query string changes when you use the filter mechanism on the ##search page. You're simply adding/subtracting catalog query criteria.
You may any of those queries in hidden fields in a search form. For example:
<form ...>
....
<input type="hidden" name="portal_type" value="Document" />
</form>
The form on the query string when you use filter is complicated a bit by its record mechanism, which allows for some min/max queries. Simple filters are much easier.
I was using Telerik MVC Grid in my project. I just wanted to change the dropdown value orders a bit. I googled for the requirement and found the filter dropdown options are handled by **telerik.grid.min.js file. But, I dont know how can i change the order from
Options by Default
Is Equal to
Is not equal to
Starts with
Contains
Does not contain
Ends with
Change to the below format
Contains
Does not contain
Starts with
Ends with
Is Equal to
Is not equal to
Can anybody tell me the possibilities that i can change the order of filter dropdown box ..
Thanks,
You can do it by JQuery simply by some codes like this :
$('#GRIDID').find(".t-filter").click(function () {
setTimeout(function () {
$(".t-filter-operator").html('<option value="substringof">Contains</option><option value="notsubstringof">Does not contain</option>');
});
});
NOTE : the above code is a sample, you should do a process to check what operators you have and then repopulate the items in desired order. You can find all allowed "option" tags by inspecting the rendered grid.
The easy way (if you're using MVC razor syntax)
#Html.Kendo().Grid<Model>().Columns(columns =>
{
columns.Bound(x => x.variableName);
})
.Filterable(filterable => filterable
.Extra(false)
.Operators(operators => operators
.ForString(str => str.Clear()
.Contains("Contains").DoesNotContain("DoesNotContain").WhateverYouNeed)
.ForEnums( dat => dat.Clear()
.IsEqualTo("Is Equal To"))
))
Here, the Clear() empties the options in the filter and then you can add the ones you want or even create your own custom ones there, simply place them there in the order that you want.
Have fun!
I am trying to use the collection action "download_csv" already present in Active Admin to download all the records of a resource. However, the action only downloads the contents of the present page. As I have paginated the resource, the data needs to be downloaded from all the pages. Any suggestions on how I can approach this problem ?
Just for future googlers. My fix (working for the current Master 1.0.0pre) is to add the following to config/initializers/active_admin.rb:
module ActiveAdmin
class ResourceController
module DataAccess
# needed for current active admin master
def max_per_page
30_000
end
def per_page
return 30_000 if %w(text/csv application/xml application/json).include?(request.format)
return max_per_page if active_admin_config.paginate == false
#per_page || active_admin_config.per_page
end
end
end
end
Replace the max as needed. This works for csv, xml and json downloads.
This answer might be a little late but hopefully it can help somebody.
Here is how I have this working in my current app:
csv do
ModelName::ATTR_ADMIN_EXPORT.each do |sym|
column sym
end
end
And in the model I have ATTR_ADMIN_EXPORT defined like this:
ATTR_ADMIN_EXPORT = [:name, :created_at]
Let me know if this works for you!
You could try this
before_filter :only => :index do
#per_page = 10 unless request.format == 'text/csv'
end
This code will also make the pagination dynamic.
before_filter :only => :index do
if params[:pag].blank?
#per_page = AdminSetting.where(:name => 'JobPagination').first.value.to_i unless request.format == 'text/csv'
else
#per_page = 10
end
end
Currently, when one searches for an item, the quick search also brings up any bundles that contain items that fit the search criteria. How would I stop this?
A solution that filters out all bundled items from search results all together would be fine too.
UPDATE
I don't want the items to show in either the catalogue or search, but am using them as upsell items. This seems to leave two options:
I could amend the search results controller to omit bundled items (the method I was asking about), or
I could change the Upsell.php script to include "Don't show individually" items.
The second is perhaps easier? Currently the filter applied is:
Mage::getSingleton('catalog/product_visibility')->addVisibleInSearchFilterToCollection($this->_itemCollection);
How would I change this so it shows don't show individually items?
Apologies for the incomplete initial question.
Second Update:
Ok, I've added
->setVisibility(null)
and it already has
->addStoreFilter()
But there is no change.
Essentially, if I don't have either of:
Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($this->_itemCollection);
Mage::getSingleton('catalog/product_visibility')->addVisibleInSearchFilterToCollection($this->_itemCollection);
Then I get the following error:
SELECT 1 AS status, e.entity_id, e.type_id, e.attribute_set_id, price_index.price, price_index.tax_class_id, price_index.final_price, IF(price_index.tier_price IS NOT NULL, LEAST(price_index.min_price, price_index.tier_price), price_index.min_price) AS minimal_price, price_index.min_price, price_index.max_price, price_index.tier_price, e.name, e.short_description, e.sku, e.price, e.special_price, e.special_from_date, e.special_to_date, e.manufacturer, e.manufacturer_value, e.small_image, e.thumbnail, e.news_from_date, e.news_to_date, e.tax_class_id, e.url_key, e.required_options, e.image_label, e.small_image_label, e.thumbnail_label, e.price_type, e.weight_type, e.price_view, e.shipment_type, e.links_purchased_separately, e.links_exist, e.is_imported, e.rc_manufacturer, e.rc_manufacturer_value, e.rc_vehicle, e.rc_vehicle_value, e.rc_assembly_type, e.rc_assembly_type_value, e.surface_type, e.surface_type_value, e.rc_drive, e.rc_drive_value, e.rc_scale, e.rc_scale_value, e.rc_motor_type, e.rc_motor_type_value, e.rc_engine_start_type, e.rc_engine_start_type_value, e.rc_engine_size, e.rc_engine_size_value, e.rc_form_factor, e.rc_form_factor_value, e.rc_frequency, e.rc_frequency_value, e.rc_gear_material, e.rc_gear_material_value, e.rc_operation, e.rc_operation_value, e.rc_torque_6v, e.rc_torque_6v_value, e.rc_speed_6v, e.rc_speed_6v_value, e.rc_bearing_type, e.rc_bearing_type_value, e.rc_waterproofing, e.rc_waterproofing_value, e.rc_battery_application, e.rc_battery_application_value, e.rc_input_supply, e.rc_input_supply_value, e.rc_power_output_amps, e.rc_power_output_amps_value, e.rc_power_output_watts, e.rc_power_output_watts_value, e.rc_lead_connector_type, e.rc_lead_connector_type_value, e.rc_gear_pitch, e.rc_gear_pitch_value, e.rc_nitro_content, e.rc_nitro_content_value, e.rc_exhaust_type, e.rc_exhaust_type_value, e.rc_engine_starter_type, e.rc_engine_starter_type_value, e.rc_head_fitting, e.rc_head_fitting_value, e.rc_temperature_rating, e.rc_temperature_rating_value, e.rc_oil_type, e.rc_oil_type_value, e.rc_container_size, e.rc_container_size_value, e.rc_class, e.rc_class_value, e.rc_paint_application, e.rc_paint_application_value, e.rc_size, e.rc_size_value, e.rc_colour, e.rc_colour_value, e.rc_pack_contents, e.rc_pack_contents_value, e.rc_spare_part_type, e.rc_spare_part_type_value, e.rc_oil_weight, e.rc_oil_weight_value, e.rc_glue_type, e.rc_glue_type_value, e.rc_usage, e.rc_usage_value, e.rc_tool_type, e.rc_tool_type_value, e.rc_engine_spare_type, e.rc_engine_spare_type_value, e.rc_tune_up_type, e.rc_tune_up_type_value, e.rc_bearing_pack_type, e.rc_bearing_pack_type_value, e.rc_driver_type, e.rc_driver_type_value, e.rc_nut_type, e.rc_nut_type_value, e.rc_plane_type, e.rc_plane_type_value, e.rc_boat_type, e.rc_boat_type_value, e.pre_order, e.pre_order_value, e.msrp_enabled, e.msrp_display_actual_price_type, e.msrp, links.link_id, link_attribute_position_int.value AS position FROM catalog_product_flat_1 AS e
INNER JOIN catalog_product_index_price AS price_index ON price_index.entity_id = e.entity_id AND price_index.website_id = '1' AND price_index.customer_group_id = 0
INNER JOIN catalog_product_link AS links ON links.linked_product_id = e.entity_id AND links.link_type_id = 4
LEFT JOIN catalog_product_link_attribute_int AS link_attribute_position_int ON link_attribute_position_int.link_id = links
I've also tried the following, but get the error:
Mage::getSingleton('catalog/product_status')->addSaleableFilterToCollection($this->_itemCollection);
Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($this->_itemCollection);
Thanks for the help.
Based on your updated question:
If you are not using Enterprise Edition TargetRule or some other module which automates upsells (i.e. the upsells are defined explicitly by the admin), then likely the simplest approach is that which you've specified - rewrite the Upsell block to not add the visibility filter. As a guess, to be optimal you may want to call setVisibility(null) and addStoreFilter() on the collection to trigger normal limiting behavior.
EDIT: Original answer below
Admin > Catalog > Manage Products grid
Choose "Bundle Product" from the filters area at the top, click "Search"
Click "Select All"
Select "Update Attributes" from the mass action block's "Action" dropdown, click "Submit"
Change the "Visibility" attribute to "Catalog"
I solved it by modifying the custom module so that I didn't need to worry about this. It may be of some use as it involved using:
$collection->addAttributeToFilter('type_id', array('neq' => 'bundle'));
Which just excludes all bundle items from a collection.