Restricting display of ads by taxonomy terms
g10tto - November 24, 2008 - 18:33
| Project: | Advertisement |
| Version: | 6.x-2.1-rc1 |
| Component: | ad_channel module |
| Category: | feature request |
| Priority: | normal |
| Assigned: | tetramentis |
| Status: | needs work |
Description
Is it possible?
I have my site divided into different age groups, with stories and ads pertaining to each.
Can I restrict ads to only appear when a user visits a certain story for that age group?

#1
Please review INSTALL.txt and README.txt that comes with the module. You can create ad groups that match your age groups, which should accomplish your requirements. (Note that the 6.x version of this module is not yet fully completed, however, so you could run into bugs.)
#2
Here is my setup:
Three ad sizes in three different blocks on the page. The placement of these do not change throughout the site, and there will always be an ad that appears in each.
Currently, the only ad groups are defined as these three positions (Banner, Sidebar, Footer).
Using Taxonomy, I divided my site's stories into 7 "age groups" (Maternity, Baby, Toddler, Child, etc.). Those age groups have subgroups relating to topics such as Health, Development, and School.
Stories are placed into these subgroups - e.g. "Healthy Afterschool Snacks" is located under Child > Health.
So I'd like to have ads that rotate within the main age groups, so that we can target our visitor who may be reading this article with an ad for Juicy Juice or clothing for young children.
I've been able to create the groups and subgroups as a new vocabulary set, but have yet to be able to restrict ads to these groups. Instead, they appear in their regular positions, rotating without specification.
Since taking your suggestion and using Taxonomy to create new ad groups, I find that the ads have only been recreated as new ad blocks, which are not actually controlled by the module's nesting terms.
Each ad should be targeted to its proper age group and only shown as the visitor navigates to different parts of the site.
-------
I know this is perhaps a lot to take in, but I thank you for your help and will continue to search for a solution.
#3
I too would like to have this feature in the ad module.
I thought that the feature "display ads based on node ids (nids), or taxonomy terms (categories)" meant what you are asking for, but maybe I was wrong.
However I found a way:
- install the pathauto module;
- go to Administer › Site building › URL aliases › Automated alias settings and enter a default path pattern for nodes (i.e. [termpath-raw]/[title-raw]) and taxonomy terms (i.e. [vocab-raw]/[catpath-raw])
- create ad groups like Baby-Banner, Baby-Sidebar, etc.
- set the new blocks to be displayed only in the corresponding pages, i.e. baby/*
I hope this helps.
It would be nice to have this feature inside the ad module, so we could not have to use pathauto and we could set an ad to be displayed for nodes with a specific tag too, or for nodes with a particular content type.
#4
Automatically closed -- issue fixed for two weeks with no activity.
#5
I find the solution of sersim a little cumbersome and not realistic.
If I got many taxonomies categories ("baby" at sersim example), it actually mean that I'll need to create for each Taxonomy category of my site 3 corresponding ad groups (for 3 different locations and banner sizes), I'll also need to associate each banner to lots of groups during the creation if I want a specific banner to be displayed across my site.
There isn't any way to call for an ad with the ad function (or whatever other dynamic way :)) in a format which state the ad group id I want and the term id of the site category that I want? (for example the 'baby' category got term id of 20 and the ad group 'wide banners' got id of 30 I'll just call the ad function like ad(20, 1, 30)).
If this feature doesn't exist how can it be implemented otherwise?
Thanks
#6
forgot to reopen :)
** and noticed that it was for the 6.x-1 and not 6.x-2 version... oops... sorry :)
#7
I found that I can make such a functionality by editing the adserve.inc file and adcache.inc
@ adserve.inc I changed line 96 to:
$variables->tids = isset($values['t']) ? preg_replace('/[^0-9,.]/', '', $values['t']) : ''; // just added the '.' string as an approved value
@ adcache.inc I edited line 221 to:
if (ereg('.', $id)) {
$tids = explode('.', $id);
$result = db_query("SELECT a.aid FROM ads a INNER JOIN term_node n ON a.aid = n.nid INNER JOIN term_node z ON a.aid = z.nid
WHERE a.adstatus = 'active' AND n.tid = %d AND z.tid = %d", $tids);
} else {
$result = db_query("SELECT a.aid FROM {ads} a INNER JOIN {term_node} n ON a.aid = n.nid WHERE a.adstatus = 'active' AND n.tid IN(%d)", $id);
}
Those changes allow me to use the ad function like this: ad('21.11', 1) which returned for display only banners which are located in an ad group with id of 21 and also in one of my ordinary site categories with id of 11.
Now I know that my hacks are "ugly" and I'm not even sure if what I did doesn't damage any other functionality (I guess it is), how can I make a decent patch out of this?
Cheers!
#8
Bumping it up again with little fixes... would love to know how this feature could be implemented
#9
I confess, it's still not clear to me what exactly you are trying to do. Please provide a very simple explanation. Try, for example, to explain what you're aiming for using two example adds "Foo" and "Bar". What groups are each in? How then are you trying to decide which pages they display on?
(Have you tried ad_channels -- they allow you to control which page an advertisement displays on based on path, though it's not clear to me whether or not this is what you're trying to do.)
#10
I rechecked ad_channels to be sure and it give a solution to my issue which is not practical to a site with lots of categories (taxonomies).
I'll try to explain my issue better now (sorry but as u can plainly see I'm not a native English speaker :)).
My site got various categories (taxonomy values) for various content sections (display articles, service providers of the field, etc..), for example:
* Sport
* Health
* Life
Each page at the site got 3 constant areas for displaying image banners, each area display banners of different size then the rest of the areas, for example:
* Top Area - 234px X 90px
* Right Area - 210px X 60px
* Bottom Area - 150px X 60px
For each image banners area I created a group ad (total 3 group ads for the entire site).
And now to my issue... :)
I want to be able to assign each banner that I create to one of the groups ad & also assign it to one or more of my site categories (taxonomy values).
So for example when a user will surf at the "Health" category he will see only banners that are associated to that specific category.
The embedding of the banner should consist of both the ad group id and the taxonomy id (tid), for example: print ad(5, 1, array('tids' => '76')); will display banners which r associated to group id 5 and also to tid 76.
I hope that I was clearer now :)
#11
#12
Okay, I see what you're trying to do now.
The way I would implement this is in ad_channels. I would add a new "Taxonomy rules" section on the channel configuration page which would allow you to select one or more terms. You could then chose to only display advertisements in this channel to nodes that are in the selected terms. I think this would be a useful feature, and will leave the issue in an active status. Patches welcome!
#13
Hm, the challenging part of this will be figuring out what taxonomy a given node is assigned to. We either have to cache this for all nodes (which could take a lot of memory on a large website), or we have to query the database each time we serve an advertisement (which would be very slow). I don't know an ideal way to solve this at the moment... unless you change the paths of your content for each taxonomy type, then you can use the existing code to match based on path.
Due to the potential memory and/or performance issues that this would cause, it's unlikely that I'll implement this.
#14
How about just creating an embedding option only without setting elaborate admin features?
For example: print ad(null, 1, array('tids' => '5, 76')); will run the current query which is located at adcache.inc line 221 but with a slight modification so the result for the above command will result in an sql query like the following:
"SELECT DISTINCT a.aid FROM {ads} a INNER JOIN {term_node} n ON a.aid = n.nid WHERE a.adstatus = 'active' AND n.tid IN(5, 76)" (I just added the DISTINCT and made the IN get multiple values).
Will that be a problem to the module?
#15
Any feature affecting ad serving needs to also be implemented in the caching layer -- this means, the functionality needs to be implemented in a way that does not require the database layer. If your site gets much traffic, the module simply won't perform well enough without a cache.
Moving issue into a pending state, which means it's waiting on a comprehensive patch or funding.
#16
I'm also highly interested in being able to display ads by taxonomy terms.
My guess is that "node-to-term" mappings could be cached on cron runs - this seems to be a solution to performance concerns. It could even be cached as an include'able PHP file with a single $array - this would allow server-side PHP caching software (like xcache) to keep that mapping in-RAM between requests. With chmod 600, caching a single variable to a PHP file shouldn't be too much of a security issue.
It also appears that http://drupal.org/node/419196 is related: if a channel is enhanced with "PHP field returns true" filter, then it would be relatively easy to put into that field term_id-checking code, and thus implement "ads by taxonomy terms" using existing 'ad channels' infrastructure.
I'll post back as soon as I'm done following your discussion in the actual module code. In the meantime, any further hints and suggestions would be highly appreciated, as I'm not really familiar with Drupal module development. Also, it would be beneficial to understand Jeremy's vision of the best approach to implement "ads by taxonomy".
#17
This one http://drupal.org/node/581450 is also related.
#18
I decided to implement the "terms selection" in channels admin, and not a "PHP field returns true" - largely for ease of use considerations (as Ad module is often used by end-users).
At the moment, I only managed to make the term selects display in a proper fieldset on channel admin page.
The following steps yet have to be performed (any help and hints would be appreciated):
- "Settings" page of the Ad module need a new fieldset "Allowed vocabularies for channels". It should list all the site's vocabularies, and allow checking which of the vocabularies will be used for term selection on the channel admin page. Reason for this fieldset: taxonomy is often used for multiple purposes within a single site, and it is not always necessary to show "ads by taxonomy" on all vocabularies (some of the vocabularies are better hidden than visible). As a more specific example: "ad groups" are implemented as taxonomy, and are already present on the channel admin page, so it's better to hide that vocabulary. Also, consider a website with forum...
- the fieldset I added needs actual code to save the terms selection
- ad_channel.inc needs code to filter display by taxonomy terms
- adache.inc needs code to work around the issues mentioned by Jeremy
Does anybody know if (and how) it is possible to add this functionality by an external module (or a sub-module)? A documentation link would be welcome.
#19
#20
I'm done with the admin part - added a new fieldset "Allowed vocabularies for channels" to Channels->Settings, and a new fieldset "Taxonomy rules" to Channel edit form. This part is fully functional now.
Getting to the actual filtering now. Will first implement non-cached filtering.
I would still appreciate information on adding my changes as a sub-module to Ad module - if my final solution won't be accepted by Jeremy into the ad_channel module. I've looked through a number of infos, but still do not quite understand how do I modify a form in ad_channel module from a new submodule:
http://groups.drupal.org/node/21725
http://drupal.org/node/508
http://drupal.org/node/206753
http://drupal.org/node/22573
Also, it's not clear if 3rd-level submodules are possible (e.g. ad_channel_taxonomy).
#21
patch
it incorporates my fix for http://drupal.org/node/606244
#22
Well, I did it. A kind of.
Let me count the number (and type) of MySQL queries added per single call of adserve.php:
Provided MySQL has a large enough queries_cache configured, I believe all these extra queries will be very fast (on the order of 0.0005 sec on a common quadcore - tested in the non-related scenario with a query returning 66k items, 5-30KiB each).
I didn't really understand how caching is supposed to work here; all the changes were done to ad_channel.inc - which seems to have no caching for URL-based filtering as well. Or is all the caching hidden under
$channels = adserve_cache('get_cache', 'channel');? If yes, then I believe #3 from the list of extra queries above could be incorporated into adcache.inc. If yes, #2 could also be cached.Finally, the firstmost query could be cached to a PHP file, as I suggested earlier. It would be wise to regenerate that cache only on node updates (I believe "Drupal actions" could help here, but I do not know for sure). Of course, that will be a specific caching - I'm not going to dump full node->taxonomy objects.
Any comments/suggestions are welcome.
Jeremy, could you please comment on your willingness to accept this functionality into the Ad module?
#23
Thanks for the patch. Some feedback after a quick read through:
I will take another look when the above are fixed. You're very much headed in the right direction, thanks for the contribution!
#24
#25
> That was done solely for the speed of development. I agree this should go into
> ad_channel table; will do that as time permits
It will be necessary before this patch will be merged.
> Yes, I understand the revisions issue. Thank you for the link (wow, that's a big list of patches
> you have there!), but I'm trying to not modify Drupal's core at all. I'll try to implement
> in-module caching (that just wasn't a priority, yet).
I would not worry about caching node_load calls -- that's outside the scope of what you're trying to do here. Besides, it's already solved when you enable the ad file cache or memcache-based cache.
I've not yet had a chance to look at your newly attached code, but suspect it needs to be modified anyway to work with the ad caches based on previous comments.