Jump to content

Recommended Posts

Hello,

Looking for a way to asychronously run the invocation code to prevent ad loading from delaying page load times.

I had looked into it previously, but ran into a roadblock because of the way the original OpenX call is structured.

I believe it had something to do with the 'document.write' command IIRC. (It has been almost a year since I reviewed working around the problem, so I may be off.)

 

Our company sites have a high saturation of ads all hosted on our servers (no third-party ads) and load times at times really slow the page down.

 

If anyone can build this feature out, that would be tremendously helpful!

And if you can code it for a Wordpress Widget plugin (possibly based off the OpenX-WP Widget) that would be even better!

Share this post


Link to post
Share on other sites

The most important reason why asynchronous loading is complicated, is that many browsers fail to correctly process and display ads that are in turn third party ad tags. Because of this, I believe nobody has been able yet to build anything that works flawlesly.

Share this post


Link to post
Share on other sites
Guest

You can use Single Page Invocation code to speed up page loads.

 

but OpenX Wordpress Widget not support the Single Page Call .

Share this post


Link to post
Share on other sites

thanks all!

 

I had left off with looking into how to rewrite the invocation code to eliminate the 'document.write' command following the outline on the article here:

http://www.stevesouders.com/blog/2012/04/10/dont-docwrite-scripts/

and

http://www.stevesouders.com/blog/2010/12/15/controljs-part-3/

 

but being that this isn't my primary job, and that I'm mainly self-taught when it comes to javascript, I wasn't comfortable with putting it into practice.

perhaps someone else can pick up the mantle?

 

i've got to assume that creating a async version of the invocation code for an ad server would be highly beneficial.

Especially since they are notoriously blamed for slow page load times, and almost entirely use the document.write statement which prevents/stops async loading of pages.

 

ultimately, ads should be seemless on a page, not affecting load times. I know real-world case isn't going to be 100% non-interferance, but anything closer, I've got to imagine is going to be benificial and give an edge in the industry.

Besides, isn't Revive all about reviving the ad server software world?

Share this post


Link to post
Share on other sites

I got ads working async in 2011 via a lot of messy workarounds. I posted how I did it on the OX forums but I think it got buried under spam and whatever else is in there.

It would be good to see Revive have a way to easily do async ad loading, but until that day comes, this is what worked for me:

1. You need to use the XMLRPC interface. So you need to copy the lib/xmlrpc/php/openads-xmlrpc.inc.php file to your website.

2. This method assumes you're using jQuery and have the migration plugin enabled, as it relies on $.browser.msie checks because it turns out IE can't handle using document.write on an iframe that is created dynamically (it'll write the content to the iframe, but it won't actually process it as being HTML content and just show everything as blank). So my workaround for that is the ad code for that impression is saved to memcache, then the iframe is set to a page that just loads the impression from memcache. A bit annoying but it works.

3. I'm also assuming you have memcached installed. You can write some sort of alternative thing that uses temporary files if you don't have memcache, but this was the simplest for me.

4. Have a line similar to this in your page:
 

$(document).ready(function() {
	$.getScript("//websitegoeshere.com/includes/openx.php");
});

5. The contents of openx.php are this (note that flat-out copypasta of this code will not work):
 

<?php

	ob_start('ob_gzhandler');
	set_time_limit(15);
	
	header('Content-Type: application/x-javascript');
	// Set $server to the location of your ad server
	$server = 'adservergoeshere.com';
	require(ROOT_DIR . '/includes/config.php');
	require(ROOT_DIR . '/includes/functions.php');
	require(ROOT_DIR . '/includes/openads-xmlrpc.inc.php');
	if (!isset($OA_context)) $OA_context = array();
	$oaXmlRpc = new OA_XmlRpc($server, '/www/delivery/axmlrpc.php', $_SERVER['HTTPS'] ? 443 : 80, $_SERVER['HTTPS'] ? true : false, 15);
	$openx = array();
	$adzones = array(
		'headerad' => 97,
		'bodyad' => 98,
		'boxtop' => 99,
		'boxmiddle' => 106,
		'boxbottom' => 100
	);
	foreach ($adzones as $key => $val) {
		$openx[$key] = $oaXmlRpc->view('zone:' . $val, 0, '', '', 0, $OA_context, 'UTF-8');
		$OA_context[] = array('!=' => 'campaignid:' . $openx[$key]['campaignid']);
	}
	
	
	foreach ($openx as $key => &$val) {
		$val['html'] = str_replace('&amp;', '&', $val['html']);
		$val['html'] = str_replace('&', '&amp;', $val['html']);
		if ($val['aSearch'] && $val['aReplace']) {
			$val['html'] = str_replace($val['aSearch'], $val['aReplace'], $val['html']);
			$val['html'] = str_replace(str_replace(array('{', '}'), array('[', ']'), $val['aSearch']), $val['aReplace'], $val['html']);
			if (extension_loaded('memcache') && (preg_match('/MSIE|Internet Explorer/i', $_SERVER['HTTP_USER_AGENT'])) && (preg_match('/^<script/i', $val['html']))) {
				$uid = uniqid();
				$val['uid'] = $uid;
				$memcache = getMemcache();
				$memcache->set('tmpad:' . $uid, $val['html'], MEMCACHE_COMPRESSED, time() + 120);
			}
		}
		//if ($_SERVER['HTTPS']) $val['logUrl'] = preg_replace('/^http:\/\//', 'https://', $val['logUrl']);
	}
	
	
	echo 'var openx = ' . json_encode($openx) . ";\n";
	
	
?>
var oxserver = "http<?php if ($_SERVER['HTTPS']) echo 's'; ?>://<?php echo $server; ?>";
$(document).ready(function() {
	for (var z in openx) {
		var adbox = $("#" + z + ".adbox"); 
		if ($(adbox).length) {
			var ad = openx[z];
			ad['spot'] = z;
			if ((ad['html'].length) || (ad['contenttype'] == 'swf')) {
				var adcontent = $(adbox).children();
				$(adbox).empty().append($("<div>").addClass("adnote").text("Advertisement")).append($("<div>").addClass("ad").append(adcontent));
				if (ad['contenttype'] == 'swf') {
					drawFlashAd(ad);
				} else {
					if ((ad['html'].substr(0, 7) == "<scr"+"ipt") || (ad['html'].substr(0, 7) == "<SCR"+"IPT")) {
						drawIFrameAd(ad);
					} else {
						$(adbox).children(".ad").html(ad['html']);
					}
				}
			} else {
				$(adbox).css({display: "none"});
			}
		}
	}
});

function drawIFrameAd(ad) {
	var oxid = "ox_" + new Date().getTime();
	var iframe = $("<iframe>").attr({name: oxid, id: oxid, width: ad['width'], height: ad['height'], frameborder: 0, scrolling: "no", vspace: 0, hspace: 0, marginheight: 0, marginwidth: 0});
	var content = "<html><body>" + ad['html'] + "</body></html>";
	if ($.browser.msie) $(iframe).attr({src: "/includes/adpage.php?ad=" + ad['uid']});
	$("#" + ad['spot'] + " > .ad").append($(iframe));
	if (!$.browser.msie) {
		var ifrm = $("#" + oxid).get(0);
		ifrm = (ifrm.contentWindow) ? ifrm.contentWindow : (ifrm.contentDocument.document) ? ifrm.contentDocument.document : ifrm.contentDocument;
		ifrm.document.open();
		ifrm.document.write(content);
		ifrm.document.close();
	}
	drawBeacon(oxid, ad);
}

function drawFlashAd(ad) {
	$.ajax({url: oxserver + "/www/delivery/fl.js", cache: true, dataType: "script", success: function() {
		var oxid = "ox_" + new Date().getTime(); 
		var oxlink = $("<a>").attr({href: ad['clickUrl']});
		var oximg = $("<img>").attr({src: ad['bannerContent'], width: ad['width'], height: ad['height'], alt: ad['alt'], title: ad['alt'], border: 0});
		$("#" + ad['spot'] + " > .ad").append($("<div>").attr({id: oxid}).css({display: "inline"}).append($(oxlink).append($(oximg))));
		var ox_swf = new FlashObject(oxserver + "/www/images/" + ad['aRow']['filename'], oxid, ad['width'], ad['height'], ad['aRow']['pluginversion']);
		var oxvars = /ox_swf\.addVariable\('([^']+)', '([^']+)'\);/g;
		var match;
		while (match = oxvars.exec(ad['html'])) {
			ox_swf.addVariable(match[1], match[2]);
		}
		ox_swf.addParam('allowScriptAccess','always');
		ox_swf.addParam('wmode', 'opaque');
		ox_swf.write(oxid);
		drawBeacon(oxid, ad);
	}});
	
}

function drawBeacon(oxid, ad) {
	var beacon = $("<div>").attr({id: "beacon_" + oxid}).css({position: "absolute", left: "0px", top: "0px", visibility: "hidden"});
	var bimg = $("<img>").attr({src: ad['logUrl'], width: 0, height: 0, alt: ""}).css({width: "0px", height: "0px"});
	$("#" + ad['spot'] + " > .ad").append($(beacon).append($(bimg)));
}

The config.php and functions.php includes just contain my passwords/server details and a getMemcache function (which just returns a memcache object). ROOT_DIR is just a reference to $_SERVER['DOCUMENT_ROOT'] that is auto-appended to the start of my pages.

The $adzones array is a list of zone IDs for your ads. The keys should be the IDs of the zones on the page (so on your page you should have <div class="adbox" id="keyname"></div> for each ad), and the values should be their corresponding ID numbers within Revive.

You'll see that there's a reference to adpage.php - this is my alternate way of getting iframe ads to work in IE. The contents of adpage.php is this:
 

<html><body><?php
	require(ROOT_DIR . '/includes/config.php');
	require(ROOT_DIR . '/includes/functions.php');
	$memcache = getMemcache();

	$adid = $_GET['ad'];
	if (!preg_match('/^[0-9A-Za-z]+$/', $ad)) die();
	
	$ad = $memcache->get('tmpad:' . $adid, MEMCACHE_COMPRESSED);
	$memcache->delete('tmpad:' . $adid);
	echo $ad;

?></body></html>

This should give you async loading for image/Flash ads as well as third-party ones. We haven't used other ad types here so I don't know how they'll go with this.

Share this post


Link to post
Share on other sites

bgrabkowitz,

 

yes iframe works fine, but brings some issue with expand tags, the best will be a native way to have asynchronous way to show any tag, it seems that the guys from openx managed to do it :

 

http://docs.openx.com/ad_server/adtagguide_asynchjs.html

 

I tried DFP async option, but it's not suitable as it seems that the just work around the issue and create an iframe with their async tag and the issue of the expand tag happen too.

 

I am not sure if it's do-able, but as Google is now ranking site depending on their speed too, I guess this kind of option will be more and more asked by publishers.

 

Wanted to share my experience and open the discussion to see what is faisable around this point.

 

Cheers,

Share this post


Link to post
Share on other sites

+1.

 

And thanks for the jquery-lazyload-ad link, I will take a look into that.

 

Installed a Lazyload script for images, and needed something similar for the banners.

 

 

In another post you said you have CloudFlare, if so, they do that Lazyload already as an option, however, not sure if you know but with CloudFlare enabled and Lazyload hosted IN your server, the AdServer will be come even more slow.

Share this post


Link to post
Share on other sites

davidm, would you mind clarifying this part of your post?

 

The config.php and functions.php includes just contain my passwords/server details and a getMemcache function (which just returns a memcache object).

 

Ideally could you post samples of your config.php and functions.php files?

Share this post


Link to post
Share on other sites

Since I've taken the time to find a solution which works for my website, I decided to pass along my solution.

This works in a jQuery environment, but doesn't depend on jQuery.

 

Using this Javascript library (available under the terms of the MIT License):

https://github.com/iamnoah/writeCapture/tree/writeCapture2

 

First, load the library, so you can use the function:

<script src="/path/to/element.write.js"></script>
<script src="/path/to/writeCapture2.js"></script>

Then simply rewrite your invocation code like so

<div id="AdPlaceholder">
   <!-- ad will go here -->
</div>

<script>
   /* this function wrapper keeps global memory space clear of random variables */
   (function(){
      var oxSrc = (document.location.protocol === "https:" ? "https:" : "http:")
         + "//example.com/ReviveAdserver/www/delivery/ajs.php"
         + "?zoneid=123&block=1&blockcampaign=1&cb=" + Math.floor(Math.random()*99999999999)
         + "&charset=UTF-8&loc=" + encodeURIComponent(window.location)
         + (document.MAX_used !== "," ? ("&exclude=" + document.MAX_used) : "")
         + (document.referrer ? ("&referer=" + encodeURIComponent(document.referrer)) : "")
         + (document.context ? ("&context=" + encodeURIComponent(document.context)) : "")
         + (document.mmm_fo ? "&mmm_fo=1" : "");
      writeCapture.write(
         document.getElementById("AdPlaceholder"),
         "<scr" + "ipt src='" + oxSrc + "'></scr" + "ipt>"
      );
   })();
</script>

If you don't need the ability to prevent displaying the same banner / campaign / advertiser on a single page, then you are done.

 

If your like me, and need campaign and advertiser blocking (to prevent duplicates), you'll have to do continue with the next step.

 

When the javascript runs the string stored in oxSrc has the current value of document.context, however subsequent ads need the revised value of document.context, to prevent duplicate ads.

 

The solution is to wrap the string creation into the javascript which is excuted asynchronously, so that the revised value of document.context is used, like so

<div id="AdPlaceholder">
   <!-- ad will go here -->
</div>

<script>
   /* this function wrapper keeps global memory space clear of random variables */
   (function(){
      writeCapture.write(
         document.getElementById("AdPlaceholder"),
         '<scr' + 'ipt>' +
            'var oxSrc = (document.location.protocol === "https:" ? "https:" : "http:")' +
            '+ "//example.com/ReviveAdserver/www/delivery/ajs.php"' +
            '+ "?zoneid=123&block=1&blockcampaign=1&cb=" + Math.floor(Math.random()*99999999999)' +
            '+ "&charset=UTF-8&loc=" + encodeURIComponent(window.location)' +
            '+ (document.MAX_used !== "," ? ("&exclude=" + document.MAX_used) : "")' +
            '+ (document.referrer ? ("&referer=" + encodeURIComponent(document.referrer)) : "")' +
            '+ (document.context ? ("&context=" + encodeURIComponent(document.context)) : "")' +
            '+ (document.mmm_fo ? "&mmm_fo=1" : "");' +
            'document.write("<scr" +  "ipt src=\'" + oxSrc + "\'></scr" + "ipt>");' +
         '</scr' + 'ipt>'
      );
   })();
</script>

Yes, this is quite ugly code, and you'll have to be careful when editing it, as it's javascript which writes javascript.

 

I hope this is able to help people, until Revive Adserver offers a direct solution to display ads asynchronously.

Share this post


Link to post
Share on other sites

Since I've taken the time to find a solution which works for my website, I decided to pass along my solution.

This works in a jQuery environment, but doesn't depend on jQuery.

 

Using this Javascript library (available under the terms of the MIT License):

https://github.com/iamnoah/writeCapture/tree/writeCapture2

 

First, load the library, so you can use the function:

<script src="/path/to/element.write.js"></script>
<script src="/path/to/writeCapture2.js"></script>

Then simply rewrite your invocation code like so

<div id="AdPlaceholder">
   <!-- ad will go here -->
</div>

<script>
   /* this function wrapper keeps global memory space clear of random variables */
   (function(){
      var oxSrc = (document.location.protocol === "https:" ? "https:" : "http:")
         + "//example.com/ReviveAdserver/www/delivery/ajs.php"
         + "?zoneid=123&block=1&blockcampaign=1&cb=" + Math.floor(Math.random()*99999999999)
         + "&charset=UTF-8&loc=" + encodeURIComponent(window.location)
         + (document.MAX_used !== "," ? ("&exclude=" + document.MAX_used) : "")
         + (document.referrer ? ("&referer=" + encodeURIComponent(document.referrer)) : "")
         + (document.context ? ("&context=" + encodeURIComponent(document.context)) : "")
         + (document.mmm_fo ? "&mmm_fo=1" : "");
      writeCapture.write(
         document.getElementById("AdPlaceholder"),
         "<scr" + "ipt src='" + oxSrc + "'></scr" + "ipt>"
      );
   })();
</script>

If you don't need the ability to prevent displaying the same banner / campaign / advertiser on a single page, then you are done.

 

If your like me, and need campaign and advertiser blocking (to prevent duplicates), you'll have to do continue with the next step.

 

When the javascript runs the string stored in oxSrc has the current value of document.context, however subsequent ads need the revised value of document.context, to prevent duplicate ads.

 

The solution is to wrap the string creation into the javascript which is excuted asynchronously, so that the revised value of document.context is used, like so

<div id="AdPlaceholder">
   <!-- ad will go here -->
</div>

<script>
   /* this function wrapper keeps global memory space clear of random variables */
   (function(){
      writeCapture.write(
         document.getElementById("AdPlaceholder"),
         '<scr' + 'ipt>' +
            'var oxSrc = (document.location.protocol === "https:" ? "https:" : "http:")' +
            '+ "//example.com/ReviveAdserver/www/delivery/ajs.php"' +
            '+ "?zoneid=123&block=1&blockcampaign=1&cb=" + Math.floor(Math.random()*99999999999)' +
            '+ "&charset=UTF-8&loc=" + encodeURIComponent(window.location)' +
            '+ (document.MAX_used !== "," ? ("&exclude=" + document.MAX_used) : "")' +
            '+ (document.referrer ? ("&referer=" + encodeURIComponent(document.referrer)) : "")' +
            '+ (document.context ? ("&context=" + encodeURIComponent(document.context)) : "")' +
            '+ (document.mmm_fo ? "&mmm_fo=1" : "");' +
            'document.write("<scr" +  "ipt src=\'" + oxSrc + "\'></scr" + "ipt>");' +
         '</scr' + 'ipt>'
      );

Yes, this is quite ugly code, and you'll have to be careful when editing it, as it's javascript which writes javascript.

 

I hope this is able to help people, until Revive Adserver offers a direct solution to display ads asynchronously.

 

digitaladapt could you post the example code of how you are calling this code. Thanks

 

ReferenceError: data is not defined
 

Share this post


Link to post
Share on other sites

Well, async loading is clearly a hot topic, so it's something to really think about for me in terms of perhaps including it on the roadmap.

 

Just for my own sanity, though - given the complexity of async loading, and as Erik has mentioned, the risks it introduces in terms of cross-browser compatibility - why is it so important to you all (i.e. those +1ing above)? Why would async loading be any better than, say, putting your standard JS tags at the bottom of the page with appropriate CSS to position them?

 

Is it just that this approach is too complex for most people to cope with, and you'd all rather have something that might not always work, but is less effort to think about in terms of just being able to drop into the site where you need the ads? Or am I missing something else?

 

Thanks.

Share this post


Link to post
Share on other sites

The main theme for wanting async loading of ad's is to increase page load speed, and not have the ad's block the loading of the main content.

 

With google now rating the site on speed + content now slow page loads will kill google page rateings.

 

Ive worked around my issue for now with using the iframe code and using jquery.load to call the ad iframe.

Share this post


Link to post
Share on other sites

Well, async loading is clearly a hot topic, so it's something to really think about for me in terms of perhaps including it on the roadmap.

 

Just for my own sanity, though - given the complexity of async loading, and as Erik has mentioned, the risks it introduces in terms of cross-browser compatibility - why is it so important to you all (i.e. those +1ing above)? Why would async loading be any better than, say, putting your standard JS tags at the bottom of the page with appropriate CSS to position them?

 

Is it just that this approach is too complex for most people to cope with, and you'd all rather have something that might not always work, but is less effort to think about in terms of just being able to drop into the site where you need the ads? Or am I missing something else?

 

Thanks.

Thanks Andrew for your reply.

As the starter of, what has become a wildfire of a thread here, I thought I'd chime in.

I've been monitoring the progress of this thread since I posted it and I still believe Asynchronous loading should be a top priority and is vital to speeding page load speeds.

And if Revive wants to be at the forefront of ad servers (which it should be), it needs to be built in.

As Redstorm stated above, page rankings are severely affected by page load times.

Yes, coders have always been able to modify, work-around or adapt, as some suggestions have been posted (which by the way are great work in the right direction), but ultimately, universal usability is going to be the Revive strong point.

Create something that doesn't get in the way of the design and usability (non-asyc currently does just that) and your market for developers has then opened up to nearly anyone looking for a competent alternative.

I can't stand Google DFP, OpenX is a joke (don't even get me started), and what are you really left with?

 

Revive has a chance to become the Unix/Unbuntu of the ad server world, but maintaining universality will be key in keeping the project at the top of the list.

I have been using OX, OAds, etc since it was still PHPads (can't recall what generation it was when I first started using it, but since early 2000s) and believe, it has the potential to be a far better ad server over the "services" provided out there.

Sans the monetized atrocity that OpenX became, OpenAds/Revive has always been about being the ad server that WORKS for those that don't want to use the alternative "services" out there.

No site admin wants to research, rewrite, or modify the invocation codes, they simply want to put it in place and manage inventory, and not have to be concerned that their "workaround" may break or degenerate to an unusable state, because the software is updated or changed.

 

Make it work, make it work right, keep it transparent within a site, and make it so ANYONE can use it.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.




×
×
  • Create New...