Hey everyone. Given there are a lot of posts with questions regarding how landers get on a CDN or how to combine PHP on a lander and why,
I decided to give it a shot to show you a simple version of a system I made for myself to have landers that run on a CDN but also benefit the powers
of dynamic programming, in my case PHP.
This is inspired from Caurmen's awesome post: Get Your Landers Up And Running On A CDN - The Simplest, Lowest-Cost Way Ever!,
everything he covers there is very up to date, do read it, it will be very useful for today's tutorial.
Ok, contents of this:
1. a link to a .zip file with all the files ( including a simple quizz landing page I used in the past - still works beautifully )
2. instructions on how to use the javascript framework - no more getUrlParam('myAwesomeUrlParam') - there is a better easier way
3. instructions about how to use the PHP included in the framework and how it works
4. how to tie all this to a CDN
Here we go.
1. As promised, here is a .zip file ( below is a picture of the folder structure, its contents and a short explanation of them ) --> click here <--

Please change the name of htaccess to .htaccess
2. The javascript framework is in the /assets/js/scripts.js file. It's not really a framework since it's just bare bones with the right tools to help you do
pretty much everything you need to do, without the need of embedding a large library like jQuery when it's not necessary.
In order to use it in the landing page, every existing function ( or whatever you decide to add to the framework ), will be accessed
via the same familiar sign $ ( like jQuery ), I'm posting the code for it here as well:
+(function () {
"use strict";
/*
* This is where we initiate the small framework.
* Every function or property will be called like this:
* $.alert();
* or
* $.params.yourparam - for URL params
*/
window.$ = window.$||{
params: {},
isInit: !1
};
$.init = function (cb) {
window.onload = function () {};
$.setProperties(function () {
cb&&cb();
});
};
/*
* To avoid calling the URL parsing function over and over,
* this section takes every parameter from the URL string
* and makes a key in the $.params object with the value specified
* in the URL
* ie: ?yourparam=yourvalue
* can be accessed like this
* $.params.yourparam
*
* Most examples make use of a variation of this by
* calling something like getUrlParam('yourparam')
*/
$.setProperties = function (cb) {
/*
* Here we capture the window.location object ( we cache it in the script )
*/
try {
$.location = JSON.stringify(window.top.location);
} catch (error) {
$.location = JSON.stringify(window.self.location);
}
var l = $.getWindowLocation();
var params = l.search.substr(1);
var pairs = params.split('&');
for (var i in pairs) {
var pair = decodeURIComponent(pairs[i]).split('=');
$.params[pair[0]] = pair[1]||!1;
}
cb&&cb();
};
/*
* This is a simple built in function for Android vibration
* Just call this in your landing page in the LP_FUNCTIONS section, like this:
* $.vibrate();
*/
$.vibrate = function (interval) {
interval = interval||[1000, 500, 1000, 500, 1000, 500, 1000, 500, 1000];
navigator.vibrate = navigator.vibrate||navigator.webkitVibrate||navigator.mozVibrate||navigator.msVibrate;
$.vibrate&&(navigator.vibrate&&navigator.vibrate(interval));
};
/*
* This takes the text inside the div with the ID 'alert' and shows it
* as alert contents
*/
$.alert = function (msg, cb) {
if ($.params.alert)
{
if (confirm($.get('#alert')))
{
cb&&cb();
}
}
};
/*
* This function returns the element with the specified ID
*/
$.id = function (id) {
return document.getElementById(id);
};
/*
* This function returns the elements with the specified CLASS
*/
$.class = function (cssClass) {
return document.getElementsByClassName(cssClass);
};
/*
* This function returns the html inside the specified HTML Selector
*/
$.html = function (selector) {
var el = document.querySelector(selector);
return el&&(function () {
return el.length>1 ? el[0].innerHTML : el.innerHTML;
})();
};
/*
* This function sets the inner HTML of an element and works like this:
* - you can specify either an ID or a CLASS
* - if a CLASS is specified, every element with that class will have that HTML inside
* - if there is a URL param with the same name as your selector ie: carrier,
* the script will fill the inner HTML with the value from the URL param or
* you can specify a default value in case that one does not exist, like so:
* $.set('#carrier', 'My default carrier');
*
*/
$.set = function (selector, value) {
var els = document.querySelectorAll(selector);
for (var i = 0; i<els.length; i++) {
var el = els[i];
el.innerHTML = value||$.params[selector.substr(1)];
}
};
/*
* This function gets the inner HTML of a selector, ID or CLASS
*/
$.get = function (selector) {
var els = document.querySelectorAll(selector);
for (var i = 0; i<els.length; i++) {
return els[i].innerHTML;
}
};
/*
* This function lets you play with browser cookies and you can use it like so:
* - $.cookie.set('mycookie', 'my value for the cookie', 1); // valid 1 day
* - $.cookie.get('mycookie'); // read the cookie value
*/
$.cookie = {
set: function (name, value, days) {
var d = new Date();
d.setTime(d.getTime()+(days*24*60*60*1000));
var expires = "expires="+d.toUTCString();
document.cookie = name+"="+value+";"+expires+";path=/";
},
get: function (name) {
name += "=";
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) {
return c.substring(name.length, c.length);
}
}
return "";
}
};
$.getWindowLocation = function () {
return JSON.parse($.location);
};
/*
* This function lets you make ajax calls for other resources if needed:
* - $.ajax.get('/my/local-resource.js'); // the default method is GET
* - $.ajax.get('/my/form.php', 'POST', function(){ alert('done'); }, {param:value});
*/
$.ajax = {
get: function (url, method, cb, data) {
var xhr = new XMLHttpRequest();
xhr.open((method||'get'), url);
if (method==='post') {
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
}
$.ajax.process(xhr, cb);
xhr.send(data);
},
process: function (xhr, cb) {
xhr.onreadystatechange = function () {
var DONE = 4; // readyState 4 means the request is done.
var OK = 200; // status 200 is a successful return.
if (xhr.readyState===DONE) {
(xhr.status===OK)&&(cb&&cb(xhr));
}
};
}
};
/*
* Here we initiate the system
*/
$.init(function () {
$.isInit = !0;
window.LPFUNCTIONS&&window.LPFUNCTIONS();
$.alert();
});
})();


Nice lander framework!
- How does this protect your landers?
- I don't think any of this really involves or requires php, just htaccess?
- jquery min from google cdn is likely to be cached already in browser, so faster than loading a custom script
- we did extensive split testing and regional servers beat a cdn in most cases
Hey mate. Good questions, will take them 1 by 1.
1. It protects the maker from ripping - this does not protect from getting into spytools for instance, that's a different topic
2. PHP in this case is for minifying / packing the JS / CSS on the fly and compiling it into one file - of course PHP can do a lot moar
3. jQuery min is around 83kb whereas the above LP with CSS / JS included is around 30kb without the extra call overhead - instant render
4. this I haven't done but if the LP is compiled as the example, the gains would be marginal
I see that most affiliates use 2-3% of jQuery just because of the ease of use for selecting a thing or 2 ( animations included )
which is both overkill and performance hog - when you want fast loading LPs, even on desktop.
As mentioned above, the LP spytool protection, cloacking even on client side, is a different topic, not in the above example.
Lemme know if I can help with it.
Cheers,
Daniel
Amazing share, thanks a lot Daniel!
Interested in the ZIP file. It is not available anymore unfortunately with the link.
Does anyone still have it?
Thanks!