Using Page Hits for Segmentation in Adobe CQ5 - adobe

I am trying to set up personalised content in CQ5 using segmentation. When I use the out of the box "Page Hits" option it doesn't work. Is there some extra configuration I have to do to use Page Hits?
I've set up two segments applied to two teaser pages. For the first one I've used
number of page hits is less than 4.
For the second I've used number of page hist is greater than 3.
Note, the teasers show up when I use Referral Keywords to test so I think the rest of the configuration is correct.
Can anyone give some advice about how to get the Page Hits segmentations to work?

Just in case anyone else has this same problem, I solved it by using a session store and set a cookie on the users browser to record how many times they had been to a particular page. Using that, I was able to configure my segments and personalise areas of the page based on number of visits the user had made to that page.
Code for the session store:
//Create the session store
if (!CQ_Analytics.MyStore) {
CQ_Analytics.MyStore = new CQ_Analytics.PersistedSessionStore();
CQ_Analytics.MyStore.STOREKEY = "MYSTORE";
CQ_Analytics.MyStore.STORENAME = "myclientstore";
CQ_Analytics.MyStore.data={};
CQ_Analytics.MyStore.findPageName = function(){
var locationName = location.pathname;
var n = location.pathname.indexOf("html");
if(n !== -1){
locationName = locationName.split('.')[0];
}
return locationName.split("/").slice(-1);
}
CQ_Analytics.MyStore.title = CQ_Analytics.MyStore.findPageName() + "-pageviews";
CQ_Analytics.MyStore.loadData = function(pageViewed) {
CQ_Analytics.MyStore.data = {"pageviewed":pageViewed};
}
CQ_Analytics.MyStore.getCookie = function(cname) {
console.log("getting the cookie");
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1);
if (c.indexOf(name) == 0){
console.log("return value for cookie is " + c.substring(name.length,c.length) );
return c.substring(name.length,c.length);
}
}
return "";
}
CQ_Analytics.MyStore.setCookie = function(cname, cvalue, exdays) {
console.log("setting the cookie");
var d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
var expires = "expires="+d.toUTCString();
document.cookie = cname + "=" + cvalue + "; " + expires;
}
CQ_Analytics.MyStore.checkCookie = function() {
console.log("checking for cookie");
var pViewd = CQ_Analytics.MyStore.getCookie(CQ_Analytics.MyStore.title);
if (pViewd != "") {
console.log("cookie is found and Viewed is " + pViewd);
pViewd = parseInt(pViewd) + 1;
CQ_Analytics.MyStore.setCookie(CQ_Analytics.MyStore.title, pViewd, 365);
CQ_Analytics.MyStore.loadData(pViewd.toString());
} else {
if (pViewd === "" || pViewd === null) {
console.log("cookie not found");
CQ_Analytics.MyStore.setCookie(CQ_Analytics.MyStore.title, "1", 365);
CQ_Analytics.MyStore.loadData("1");
}
}
}
CQ_Analytics.MyStore.checkCookie();
}
//register the session store
if (CQ_Analytics.CCM){
CQ_Analytics.CCM.register(CQ_Analytics.MyStore)
}
The most useful documentation I found was this: https://docs.adobe.com/docs/en/cq/5-6-1/developing/client_context_detail.html#par_title_34

Related

SSR for A/B tests in Sveltekit

Given 2 scenarios:
Making A/B tests for website (with SSR).
Making server side rendered UI depends on user's settings.
What would be the correct approach with this tasks with Sveltekit?
use: directive that instantiate dynamically loaded components depends on cookie that passed to it?
Good topic!
I think it can be done this way:
<script>
import { browser } from '$app/environment';
let testName='testname'; // info about test - name of test
let testVersion='0'; // version - '1','2','3','4'
let testLengthDays=30; // number of days for testing
function setCookie(cname, cvalue, exdays) {
const d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
let expires = "expires="+ d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
function getCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(';');
for(let i = 0; i <ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
//Test if browser
if (browser) {
if (getCookie(testName)=="") {
//Test if cookie exists (2 means that it is A/B test, it can be changed to 3 for A/B/C etc.)
testVersion=(Math.floor(Math.random() * 2) + 1).toString()
setCookie(testName, testVersion, testLengthDays)
} else {
testVersion=getCookie(testName)
}
}
</script>
{#if testVersion==='1'}
Test version 1
{:else}
Test version 2
{/if}
But it is not SSR, it is fully client-site

Restrict typeform to single submission on Wordpress post

Have a simple typeform embedded into a post in Wordpress. Nothing fancy at all. Embed code pulled direct from Typeform.
However, people can submit multiple times. ie. One person could theoretically do it 100 times.
Typeform have advised a cookie will solve this, and restrict a user to a single submission - but really do not know where to begin there. Is there a simple, quick fix that could do such a thing? Any ideas completely welcome!
One of the solutions could be only showing the embedded typeform if the cookie does not exist.
not really sure how you would do this in Wordpress.
But the logic is:
const embedElement = document.querySelector('.target-dom-node')
const displayed = getCookie("displayed_typeform");
if (displayed){
embedElement.innerHTML="<h2>Typeform already displayed once.</h2>"
} else if(!displayed && displayed === "") {
setCookie("displayed_typeform", true, 365);
showEmbed();
}
setCookie and getCookie are two functions that deal with cookie management
function setCookie(cname, cvalue, exdays) {
var d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
var expires = "expires="+ d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
function getCookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for(var i = 0; i <ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
You can find a complete project that demonstrates this feature here.

Issues loading Firebase data into web application

I am having problems in my web application regarding loading the data into the application.
The application looks like this:
The data is saved into the database under the users display name. The code looks like this to save the data:
function saveToFB(bookName) {
var user = firebase.auth().currentUser;
name = user.displayName;
firebase.database().ref('Book/' + name).push({
book: bookName,
});
};
So when the user saves the data it is saved under a node which is their display name. I currently have 2 signed up users both with different display names and different data within each. The JSON looks like so:
However, when it comes to loading the data into the application I am having some issues. Rather than loading the data corresponding to the currently signed in user, it simply loads the data from the last signed in user.
As you can see from this screenshot - The console clearly states that Joe is logged in but is being shown George's data.
Not even refreshing the page populates the application with the correct data. I first have to add a new book, which does not get displayed as it is under Joe not George, and only then once I refresh the page does it show Joe's data.
But then the issue occurs again when I sign back out and into another account and the previous data is displayed.
My JS for the rest of the application looks like this:
function refreshUI(list) {
var lis = '';
var lis2 = '';
var lis3 = '';
for (var i = 0; i < 10 && i < list.length; i++) {
lis += '<li style="width: 150px" data-key="' + list[i].key + '">' + list[i].book + genLinks(list[i].key, list[i].book) +'</li>';
};
for (var i = 10; i < 20 && i < list.length; i++) {
lis2 += '<li style="width: 150px" data-key="' + list[i].key + '">' + list[i].book + genLinks(list[i].key, list[i].book) +'</li>';
};
for (var i = 20; i < 30 && i < list.length; i++) {
lis3 += '<li style="width: 150px" data-key="' + list[i].key + '">' + list[i].book + genLinks(list[i].key, list[i].book) +'</li>';
};
document.getElementById('bookList').innerHTML = lis;
document.getElementById('bookList2').innerHTML = lis2;
document.getElementById('bookList3').innerHTML = lis3;
};
function genLinks(key, bkName) {
var links = '';
links += '<i id="deleteBook" class="material-icons">delete</i> ';
links += '<i id="removeBook" class="material-icons">clear</i> ';
links += '<i id="selectBook" class="material-icons">check</i>';
return links;
};
function del(key, bkName) {
var deleteBookRef = buildEndPoint(key);
deleteBookRef.remove();
}
function select(data, book, key) {
document.getElementById('selectBook').style.color="blue";
document.getElementById('selectBook').style.color="blue";
var selectBookRef = book;
document.getElementById('alltext').value += selectBookRef + ',';
}
function buildEndPoint (key) {
return new Firebase('https://project04-167712.firebaseio.com/Book/' + '/' + name + '/' + key);
}
var bookList = firebase.database().ref('Book/' + name);
// The issue - I think
bookList.on("value", function(snapshot) {
var data = snapshot.val();
var list = [];
for (var key in data) {
if (data.hasOwnProperty(key)) {
book = data[key].book ? data[key].book : '';
if (book.trim().length > 0) {
list.push({
book: book,
key: key
})
}
}
}
refreshUI(list);
});
What i'm looking for is for a user to log into their account and see their data and no one else's.
Any help with this issue would be great - This is the only method i've tried so far to only show the user their data and not all the other users' data along with it - So if there are any other suggestions on how to do this i'd appreciate it.

Show static non-clickable heading in AutoCompleteExtender list

I have an AutoCompleteExtender from the Ajax Control Toolkit. I need to have a heading in the dropdown list that shows how many items found, but it should not be selectable as an item.
I have tried this using jQuery, but even when I just add as a div, it is still selected as an item into the text box when I click on it:
function clientPopulated(sender, e) {
var completionList = $find("AutoCompleteEx").get_completionList();
var completionListNodes = completionList.childNodes;
for (i = 0; i < completionListNodes.length; i++) {
completionListNodes[i].title = completionListNodes[i]._value.split(':')[2];
}
var resultsHeader;
if(completionListNodes.length==1000)
resultsHeader = 'Max count of 1000 reached.<br/>Please refine your search.';
else if(completionListNodes.length>0)
resultsHeader = completionListNodes.length + ' hits.';
else
resultsHeader = msg_NoObjectsFound ;
jQuery(completionListNodes[0]).before('<div>' + resultsHeader + '</div>');
}
Add OnClientItemSelected and OnClientShowing events handlers and try script below:
function itemSelected(sender, args) {
if (args.get_value() == null) {
sender._element.value = "";
}
}
function clientShowing() {
var extender = $find("AutoCompleteEx");
var optionsCount = extender.get_completionSetCount();
var message = "";
if (optionsCount == 1000) {
message = 'Max count of 1000 reached.<br/>Please refine your search.';
}
else if (optionsCount > 0) {
message = optionsCount + " hits."
}
else {
message = "oops."
}
jQuery(extender.get_completionList()).prepend("<li style='background-color:#ccc !important;'>" + message + "</li>");
}
Added:
you even can do this without OnClientItemSelected handler:
function clientShowing() {
var extender = $find("AutoCompleteEx");
var oldSetText = extender._setText;
extender._setText = function (item) {
if (item.rel == "header") {
extender._element.value = "";
return;
}
oldSetText.call(extender, item);
};
var optionsCount = extender.get_completionSetCount();
var message = "";
if (optionsCount == 1000) {
message = 'Max count of 1000 reached.<br/>Please refine your search.';
}
else if (optionsCount > 0) {
message = optionsCount + " hits."
}
else {
message = "oops."
}
jQuery(extender.get_completionList()).prepend("<li rel='header' style='background-color:#ccc !important;'>" + message + "</li>");
}
We can give a better answer if you post the output html of your autocomplete control. Anyway if its a dropdown control;
jQuery(completionListNodes[0]).before('
<option value="-99" disabled="disabled">your message here</option>'
);
The answer by Yuriy helped me in solving it so I give him credit although his sollution needed some changes to work.
First of all, the clientShowing event (mapped by setting OnClientShowing = "clientShowing" in the AutoExtender control) is executed on initialization. Here we override the _setText method to make sure nothing happens when clicking on the header element. I have used the overriding idea from Yuriy's answer that really did the trick for me. I only changed to check on css class instead of a ref attribute value.
function clientShowing(sender, e) {
var extender = sender;
var oldSetText = extender._setText;
extender._setText = function (item) {
if (jQuery(item).hasClass('listHeader')) {
// Do nothing. The original version sets the item text to the search
// textbox here, but I just want to keep the current search text.
return;
}
// Call the original version of the _setText method
oldSetText.call(extender, item);
};
}
So then we need to add the header element to the top of the list. This has to be done in the clientPopulated event (mapped by setting OnClientPopulated = "clientPopulated" in the AutoExtender control). This event is executed each time the search results have been finished populated, so here we have the correct search count available.
function clientPopulated(sender, e) {
var extender = sender;
var completionList = extender.get_completionList();
var completionListCount = completionList.childNodes.length;
var maxCount = extender.get_completionSetCount();
var resultsHeader;
if(completionListCount == maxCount)
resultsHeader = 'Max count of ' + maxCount + ' reached.<br/>'
+ 'Please refine your search.';
else if(completionListCount > 0)
resultsHeader = completionListCount + ' hits.';
else
resultsHeader = 'No objects found';
jQuery(completionList).prepend(
'<li class="listHeader">' + resultsHeader + '</li>');
}
I have also created a new css class to display this properly. I have used !important to make sure this overrides the mousover style added from the AutoExtender control.
.listHeader
{
background-color : #fafffa !important;
color : #061069 !important;
cursor : default !important;
}

keep JavaScript array variable during post-back

How can I keep the values of ;ctrlIDhdnImageSourceArrayJs,ctrlIDhdnElementsArayJsHidden during a web page life-cycle...
"<script language = javascript>
debugger;
var ctrlIDhdnImageSourceArrayJs = '" + this.hdnImageSourceArrayJs.ClientID + #"';
var ctrlIDhdnElementsArayJsHidden = '" + this.hdnElementsArayJsHidden.ClientID + #"';
var loaderF = function getImagesData()
{
var fieldNamesList=[" + fieldNames + #"];
return KrediKartUtils.LoadImagesData('0','" + KrediKartiRow.Row.SmartPenFormNo + #"',fieldNamesList,LoadImagesDataCallBack);
};
function LoadImagesDataCallBack()
{
if(images.length > 0)
{
var numImages = 10; /*10 ar 10 ar göster*/
while(images.length > 0 && numImages-- > 0)
{
document.getElementById(elements.shift()).src =images.shift();
}
/* setTimeout(fetchImages, 1000); *//*1sn de bir*/
LoadImagesDataCallBack();
}
}
if('False' == '" + Page.IsPostBack.ToString() + #"')
{
var images=[" + imageSourceArrayJs + #"];
var elements=[" + elementsArayJs + #"];
document.getElementById(ctrlIDhdnImageSourceArrayJs).value="""+imageSourceArrayJs+#""";
document.getElementById(ctrlIDhdnElementsArayJsHidden).value="""+elementsArayJs+#""";
window.onload = loaderF;
}else{
var images=[document.getElementById(ctrlIDhdnImageSourceArrayJs).value];
var elements=[document.getElementById(ctrlIDhdnElementsArayJsHidden).value];
LoadImagesDataCallBack();
}
</script>";
To keep any value or values during a new request, you will need to include those values with the request.
This means that for a GET, you need to include the values in the querystring
?myValue=1&myArray=1,2,3,4,5
And for a POST you need to append your values to the posted data (usually by placing them inside form fields during the "onsubmit" event.
You can then either process these server side and write out their value to the page or retrieve them from the document.location using JavaScript.

Resources