I currently have an SCA website that has sub categories that need to display as a category page, and not a Product listing page. (i.e. display the categories, not the products).
Currently, I have modified the isCategoryPage to override the Facets.Views.isCategoryPage such that it does this correctly. However, when doing a search on the site - it breaks that page with a blank page.
I am currently stuck at figuring out how to detect if I am on a search page rather than a category page.
The code is thus:
...
// #Overrides Facets.Views.isCategoryPage
isCategoryPage: function isCategoryPage(translator) {
var currentFacets = translator.getAllFacets();
var categories = translator.getCategoryPath();
if (<--IsSearchPage() === true --->) {
return (_.keys(categories[categories.length-1].categories).length !== 0);
} else {
return (currentFacets.length === 1 &&
currentFacets[0].id === 'category' &&
categories &&
CategoryHelper.showCategoryPage(categories)
);
}
},
...
As you can see the if statement is where I need a bit of help.
if (<--IsSearchPage() === true --->) {
What method, function, code would detect if the page is a search page. Or if the page url has /search in the url. (either would work).
Thank you.
The proper update, after much trial and error:
isCategoryPage: function isCategoryPage(translator) {
var currentFacets = translator.getAllFacets();
var categories = translator.getCategoryPath();
if (categories) {
return (_.keys(categories[categories.length-1].categories).length !== 0);
} else {
return (currentFacets.length === 1 &&
currentFacets[0].id === 'category' &&
categories &&
CategoryHelper.showCategoryPage(categories)
);
}
},
Related
I have this code installed on my website and what it is suppose to do is see if a product has a single or double attribute and then it disables products from there that are out of stock so customers can't click on it. The code works great for the single attribute products but it doesn't seem to work for the double attribute products.
Single Attribute Product link - https://true-grit-running-company.shoplightspeed.com/goodr-sunglasses.html
Double Attribute Product link - https://true-grit-running-company.shoplightspeed.com/womens-bondi-7.html?id=65554420&quantity=1
`
// A quick check to see if it is a product being viewed (checking the microdata) - to avoid running the rest of the code if viewing a page other than the product page
if ($('[itemtype*="//schema.org/Product"]').length > 0) {
//Check the url to see if a variant is being viewed or not
var curl = location.href;
//choose the appropriate ajax url
if (curl.indexOf('?') > -1) {
var url = curl + '&format=json';
} else {
var url = '?format=json';
}
//Start the ajax call
$.ajax({
url: url,
})
// Add the disabled attribute to the variants that aren't available
.done(function(obj) {
//create a variable with the product variants
var data = obj.product.variants;
//fun a function on each variant
$.each(data, function(index, value) {
//check if any of the variants aren't available for purchase
if (!value.stock.available) {
//CODE FOR DOUBLE ATTRIBUTE VARIANTS
//check if the variants are double attribute
if (value.title.indexOf(',') > -1) {
console.log('Double Attribute matrix!');
var attribute1 = value.title.replace(/"/g,'').split(',')[0].split(": ")[1];
//only disable the variants for which the first attribute is being viewed
if ($('select[name*="matrix"]:first()').val() == attribute1) {
var option = value.title.replace(/"/g,'').split(',')[1].split(":")[1];
$('select[name*="matrix"] option:contains(' + option + ')').each(function(){
if ($(this).text() == option) {
$(this).attr('disabled', 'true');
}
});
}
//CODE FOR SINGLE ATTRIBUTE VARIANTS
} else {
console.log('Single Attribute matrix!');
var option = value.title.split(': ')[1];
var selectname = value.title.split(': ')[0];
$('select[name*="matrix"] option:contains(' + option + ')').each(function(){
if ($(this).text() == option) {
$(this).attr('disabled', 'true');
}
});
}
}
})
});
} else {
console.log('not a product page!');
}
`
I've noticed something weird about our prestashop store - the category description that's displayed on page 1 disappears when the customer switches to any other page.
https://vipkoszulka.pl/91-pielegniarka
https://vipkoszulka.pl/91-pielegniarka?page=2
(below the products, above the footer. the div contains category title as well)
Furthermore, if you go from page 1 to any other page and then back to page 1, the category description is gone as well. The div that's supposed to contain all the info (#js-product-list-bottom) is just empty.
Can someone point me out which controller is responsible for this? I found part of the script that's responsible for pagination in ProductListingFrontController.php:
ProductSearchQuery $query,
ProductSearchResult $result
) {
$pagination = new Pagination();
$pagination
->setPage($query->getPage())
->setPagesCount(
(int) ceil($result->getTotalProductsCount() / $query->getResultsPerPage())
)
;
$totalItems = $result->getTotalProductsCount();
$itemsShownFrom = ($query->getResultsPerPage() * ($query->getPage() - 1)) + 1;
$itemsShownTo = $query->getResultsPerPage() * $query->getPage();
$pages = array_map(function ($link) {
$link['url'] = $this->updateQueryString(array(
'page' => $link['page'] > 1 ? $link['page'] : null,
));
return $link;
}, $pagination->buildLinks());
//Filter next/previous link on first/last page
$pages = array_filter($pages, function ($page) use ($pagination) {
if ('previous' === $page['type'] && 1 === $pagination->getPage()) {
return false;
}
if ('next' === $page['type'] && $pagination->getPagesCount() === $pagination->getPage()) {
return false;
}
return true;
});
return array(
'total_items' => $totalItems,
'items_shown_from' => $itemsShownFrom,
'items_shown_to' => ($itemsShownTo <= $totalItems) ? $itemsShownTo : $totalItems,
'current_page' => $pagination->getPage(),
'pages_count' => $pagination->getPagesCount(),
'pages' => $pages,
// Compare to 3 because there are the next and previous links
'should_be_displayed' => (count($pagination->buildLinks()) > 3),
);
}
But it only deals with products, not the description itself.
This is not really an issue. As long as you don't have a description on the second page, it's ok from the SEO perspective. The most important is to have a description available on the first page when you visit the page directly.
By default App Insights use page title as event name. Having dynamic page names, like "Order 32424", creates insane amount of event types.
Documentation on the matter says to use trackEvent method, but there are no examples.
appInsights.trackEvent("Edit button clicked", { "Source URL": "http://www.contoso.com/index" })
What is the best approach? It would be perfect to have some sort of map/filter which would allow to modify event name for some pages to the shared name, like "Order 23424" => "Order", at the same time to leave most pages as they are.
You should be able to leverage telemetry initializer approach to replace certain pattern in the event name with the more "common" version of that name.
Here is the example from Application Insights JS SDK GitHub on how to modify pageView's data before it's sent out. With the slight modification you may use it to change event names based on their appearance:
window.appInsights = appInsights;
...
// Add telemetry initializer
appInsights.queue.push(function () {
appInsights.context.addTelemetryInitializer(function (envelope) {
var telemetryItem = envelope.data.baseData;
// To check the telemetry item’s type:
if (envelope.name === Microsoft.ApplicationInsights.Telemetry.PageView.envelopeType) {
// this statement removes url from all page view documents
telemetryItem.url = "URL CENSORED";
}
// To set custom properties:
telemetryItem.properties = telemetryItem.properties || {};
telemetryItem.properties["globalProperty"] = "boo";
// To set custom metrics:
telemetryItem.measurements = telemetryItem.measurements || {};
telemetryItem.measurements["globalMetric"] = 100;
});
});
// end
...
appInsights.trackPageView();
appInsights.trackEvent(...);
With help of Dmitry Matveev I've came with the following final code:
var appInsights = window.appInsights;
if (appInsights && appInsights.queue) {
function adjustPageName(item) {
var name = item.name.replace("AppName", "");
if (name.indexOf("Order") !== -1)
return "Order";
if (name.indexOf("Product") !== -1)
return "Shop";
// And so on...
return name;
}
// Add telemetry initializer
appInsights.queue.push(function () {
appInsights.context.addTelemetryInitializer(function (envelope) {
var telemetryItem = envelope.data.baseData;
// To check the telemetry item’s type:
if (envelope.name === Microsoft.ApplicationInsights.Telemetry.PageView.envelopeType || envelope.name === Microsoft.ApplicationInsights.Telemetry.PageViewPerformance.envelopeType) {
// Do not track admin pages
if (telemetryItem.name.indexOf("Admin") !== -1)
return false;
telemetryItem.name = adjustPageName(telemetryItem);
}
});
});
}
Why this code is important? Because App Insights use page titles by default as Name for PageView, so you would have hundreds and thousands of different events, like "Order 123132" which would make further analysis (funnel, flows, events) meaningless.
Key highlights:
var name = item.name.replace("AppName", ""); If you put your App/Product name in title, you probably want to remove it from you event name, because it would just repeat itself everywhere.
appInsights && appInsights.queue you should check for appInsights.queue because for some reason it can be not defined and it would cause an error.
if (telemetryItem.name.indexOf("Admin") !== -1) return false; returning false will cause event to be not recorded at all. There certain events/pages you most likely do not want to track, like admin part of website.
There are two types of events which use page title as event name: PageView
and PageViewPerformance. It makes sense to modify both of them.
Here's one work-around, if you're using templates to render your /orders/12345 pages:
appInsights.trackPageView({name: TEMPLATE_NAME });
Another option, perhaps better suited for a SPA with react-router:
const Tracker = () => {
let {pathname} = useLocation();
pathname = pathname.replace(/([/]orders[/])([^/]+), "$1*"); // handle /orders/NN/whatever
pathname = pathname.replace(/([/]foo[/]bar[/])([^/]+)(.*)/, "$1*"); // handle /foo/bar/NN/whatever
useEffect(() => {
appInsights.trackPageView({uri: pathname});
}, [pathname]);
return null;
}
I want that whenever a user visits a certain page with Project Center webpart in it, she should have her View already set (forced) e.g. "Summary", "Earned Value" etc.
I know that the view is bound to the user's last session, so if during her last visit the user changed the View into "Earned Value", the next one will be "Earned value".
How can I force that everytime a user opens the page with Project Center webpart, she will always open the "Summary" view?
Thanks.
This is a JavaScript solution I wrote that uses a query string parameter "viewuid" (GUID for the view) to set the view
var projCenterExt;
var JsGridSatellite;
_spBodyOnLoadFunctionNames.push("projCenterChangeView")
function projCenterChangeView()
{
if (window.location.search.toLowerCase().indexOf("viewuid") >= 0)
{
var JsGridViewUid = window.location.search.toLowerCase().split("viewuid=")[1].split("&")[0];
if (typeof projectCenterComponent !== 'undefined')
{
if (typeof JsGridSatellite === 'undefined') JsGridSatellite = projectCenterComponent.get_GridSatellite();
JsGridSatellite.LoadNewView({uid: JsGridViewUid});
}
}
}
Thanks Papa Daniel. You got us started but this would only work in Chrome. We had to add a pause in there and then it worked in I.E. Just to be clear, you need to find the GUID of the view you want to display and use that in your hyperlink.
Here is my example
http://projectserver/PWA/SitePages/ITDDash.aspx?idViewUID=38f25d41-2391-4ed4-b84e-2befec36b80b
var projCenterExt;
var JsGridSatellite;
_spBodyOnLoadFunctionNames.push("projCenterChangeView")
//console.debug("before projCenterChangeView");
function projCenterChangeView()
{
//alert("in projCenterChangeView");
//console.debug("before 3 secs");
setTimeout(function(){
//alert("in if:"+window.location.search.toLowerCase().indexOf("viewuid") );
if (document.location.search.toLowerCase().indexOf("viewuid") >= 0)
{
var JsGridViewUid = document.location.search.toLowerCase().split("viewuid=")[1].split("&")[0];
//alert("in if:"+JsGridViewUid );
if (typeof projectCenterComponent !== 'undefined')
{
if (typeof JsGridSatellite === 'undefined'){
//console.debug("JsGridSatellite kis undefined");
JsGridSatellite = projectCenterComponent.get_GridSatellite();
//alert("jjc test");
}
JsGridSatellite.LoadNewView({uid: JsGridViewUid}); //orig
}
//JsGridSatellite.LoadNewView({uid: JsGridViewUid});
}
//console.debug("after 3 secs");
}, 1000);
//alert("at end");
}
I've created a basic extension that searches Google if the URL/HTML content fulfill certain requirements. It works for the most part, but fails miserably when there are multiple instances of the extension. For example, if I load tab A and then tab B, but click on the page action for tab A, I will be directed to a search of tab B's content.
I don't know how to silo the script to each tab, so that clicking tab A's page action will always result in a search for tab A stuff. How can that be done? I'd appreciate your suggestions!
background.js
title = "";
luckySearchURL = "http://www.google.com/search?btnI=I%27m+Feeling+Lucky&ie=UTF-8&oe=UTF-8&q=";
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.title != "") {
title = request.title;
sendResponse({confirm: "WE GOT IT."});
}
});
chrome.tabs.onUpdated.addListener(function(tabId, change, tab) {
if (change.status === "complete" && title !== "") {
chrome.pageAction.show(tabId);
}
});
chrome.pageAction.onClicked.addListener(function(tab) {
chrome.tabs.create({url: luckySearchURL + title})
})
contentscript.js
function getSearchContent() {
url = document.URL;
if (url.indexOf("example.com/") > -1)
return "example";
}
if (window === top) {
content = getSearchContent();
if (content !== null) {
chrome.runtime.sendMessage({title: content}, function(response) {
console.log(response.confirm); })
};
}
You could do something like store the title with its associated tabId, that way when you click on the pageAction it uses the correct title. The changes would be just these:
background.js
title= [];
[...]
chrome.runtime.onMessage.addListener(function(request,sender,sendResponse){
if (request.title != "") {
title.push({tabId:sender.tab.id, title:request.title});
sendResponse({confirm: "WE GOT IT."});
}
});
[...]
chrome.pageAction.onClicked.addListener(function(tab) {
title.forEach(function(v,i,a){
if(v.tabId == tab.id){
chrome.tabs.create({url: luckySearchURL + v.title});
// Here I am going to remove it from the array because otherwise the
// array would grow without bounds, but it would be better to remove
// it when the tab is closed so that you can use the pageAction more
// than once.
a.splice(i,1);
}
});
});
You're facing this issue because of window === top. So your title variable gets its value from the last opened tab. So if B is opened after A, title gets its value from B. Try this: Detect Tab Id which called the script, fetch the url of that tab, which then becomes your title variable. As below:
chrome.pageAction.onClicked.addListener(function(tab) {
chrome.tabs.query({active:true},function(tabs){
//this function gets tabs details of the active tab, the tab that clicked the pageAction
var urltab = tabs[0].url;
//get the url of the tab that called this script - in your case, tab A or B.
chrome.tabs.create({url: urltab + title});
});
});