drupal

Using Google AdSense in Drupal

Submitted by tomo on October 8, 2012 - 10:11pm

Recently I attended a BarCamp where there was a session about monetizing blogs for a very modest monthly income, although an amount that amounts to a lot for a local blogger. With Drupal, setting up Google AdSense content is easy.

First, just copy the code generated from Adsense into a new block using the block admin interface. Be sure to save the node with the PHP Input Filter (you may need to give yourself permission in admin/permissions to use this powerful filter). Full HTML filter is not sufficient for AdSense code as it will break the finicky JavaScript, so use PHP which performs no filtering or transformations or create a new input filter that does no filtering.

You may want to create a special region (by editing the .info file for your theme and adding a new line, then refreshing cache to see it in the dropdown in blocks admin) for your ads otherwise use an existing region to place the block. If you already have regions like a sidebar that has space for content in the same dimensions (especially width) as your chosen AdSense ad then you won't need to do anything. If you want to optimize your ads though it's recommended, even by Google themselves, to choose larger ad sizes - especially large square ads.

For placing the node somewhere within the node's content, it's trickier as you can't place it use the block admin interface which only deals with regions that are defined in .info and made available via preprocess functions to your page.tpl.php. You can still use blocks to contain the code though. So create a new block, then look for the number in the URL which is the block id. Then you can manually place that block's content anywhere with this code:

$block = module_invoke('block', 'block', 'view', <BLOCK_ID_HERE>);
print $block['content'];

When publishing your ad blocks, if they don't appear at first and you see "Bad Request 400" in Chrome's Developer JavaScript Console, you can try waiting and may magically go away after awhile. That's what happened to me.

There's also an AdSense module (http://drupal.org/project/adsense) which makes this all a bit easier, but as you can see it's not hard at all to do manually, which means one less module on your system to complicate things.

But here are some other things the Drupal AdSense module can do:


The module provides easy-to-use ad blocks.
You can easily disable the ads for certain roles.
Provides simple controls for troubleshooting the ads before going live with the site.
If Google changes some minor details in the script in , your script can be updated site-wide just by upgrading the module.
If you want to do ad revenue sharing, there's really no other option

This technique can be used for other online advertising networks besides Google AdSense. It could just as easily be used for Amazon.com's affiliate program. If you're in Vietnam you might consider one of the burgeoning number of Vietnamese online ad networks, although they won't have anything like the inventory of Google.

How can we store tables or spreadsheets in Drupal content nodes?

Drupal is a Content Management System as well as a Content Management Framework. It's meant for facilitating the creation and editing of content, where content doesn't just mean simple text. CCK allows Drupal site managers to easily enable complex data types for their content. But sometimes it's not so easy to manage lots of simple data in the way that a spreadsheet (meaning Excel or Google Spreadsheet) easily manages many rows and columns of related data.

Sometimes you really want tabular data and you may not know for sure how many rows or columns you'll want beforehand, which is never a problem for Excel or Google Spreadsheet (which is also why sometimes people abuse Excel as a general purpose database). Maybe you are importing spreadsheets or are using spreadsheets with many rows and columns, and only want to use a section of the spreadsheet. Maybe you need to use spreadsheets because you are using formulas and want to do some graphing based on some numbers too. In fact, Excel can do much more. Rather than hoping all of those use cases will make it into a Drupal module anytime soon, wouldn't it be nice if you could just embed a spreadsheet in a node?

There are some modules for attaching tables or tabular data to nodes but in the end the interface can be a bit unwieldy. I discussed building something like a spreadsheet to quickly edit many values and below I present a demonstration.

What is already available that we could use to attach spreadsheets or something similar to nodes?

1. You could: Configure a Google spreadsheet that's either public or somehow accessed via a Google api, perhaps using OAuth2 or just assuming the viewer also has edit access to the spreadsheet. Google already lets you embed spreadsheets including the editable spreadsheet but they don't let you limit the view of the spreadsheet (limiting the view still lets everyone access the whole spreadsheet by changing the URL).

We would also need new nodes to automatically create sheets in the spreadsheet or new spreadsheets altogether and embed them in node edit. This would need to use their APIs since the embeddable Google Spreadsheets require an existing spreadsheet, otherwise this step needs to be done manually for each node - a new Google spreadsheet created per node.

This Redmine Google Docs plugin takes a similar approach and shows how the resulting data could be embedded.

(This might be worth investigating as well.)

2. Another approach would be to take an existing JavaScript or Java spreadsheet that could be embedded. This could be exactly what you want if you need the full functionality of Excel in each node. One such online spreadsheet is ZK Spreadsheet which is written in Java, and would let you have full formula and charting support.

3. Embed a widget like the form below as a CCK field in a node. It would be a new CCK field type where the editing widget is the below spreadsheet-like table and the display widget might be the same thing, an uneditable table, or the raw JSON string representation. In the database, the actual value of the field would be JSON (unless you wanted to use PHP's serialize() which would require POSTing values first instead of just posting the json value). This means you wouldn't relate or compare this field to anything else, as with any serialized data in a database. You could come up with some other schema involving columns and rows to store the table's values for each field in a node but I'm not sure it's worthwhile.

I created this demonstration but haven't turned it into a Drupal module. There is code to dump the edited values into a single JSON value to be stored in the database but the storage would be module-specific.

Get the JavaScript - then combine it with html and CSS, which you also see below.

.
A
B
C
+
1
2
3
+
JSON: "

"

Drupal ImageCache Image Quality

Submitted by tomo on September 26, 2012 - 11:04am

The problem is this. ImageCache is a great simple way to transform random images into useful dimensions, etc. But sometimes the uploaded image is already exactly the quality and even dimensions we want. But after imagecache module runs, the file size is actually larger than the original while the quality has gone down, despite JPG image quality being 100% (default is set to 75%). One workaround can be to re-sharpen the image (imagecache_sharpen) but this also loses some quality.

1. Check that the uploaded image (metadata saved as CCK field, file stored directly in sites/default/files) has not been degraded in quality.

2. Check that minimum/maximum resolution for the image fields (CCK) are set to 0 (no restriction) so that they aren't accidentally resized at the upload to CCK step.

3. Run "drush imagecache-flush" in case you have files left over from a recent imagecache configuration change.

4. Try replacing GD with ImageMagick. If you stick with GD, and try compiling a newer GD library. ImageMagick by default can output higher quality images than GD.

How does Drupal's image resizing and processing work?

ImageCache goes through imageapi which uses different image processing functions based on the library (by default GD and ImageMagick support are provided) used.

Any resizing operation will result in a change (loss) in quality. That is to be expected since upsizing creates new pixels from single original pixels without having new information (unlike the magical effects of zooming into images on CSI shows) and downsizing will generally cause information to be lost and many pixels will "store" the information from several surrounding pixels.

So only operations that keep the image the same dimensions or crop the image (in which case the cropped portion has the same dimensions in both old and new files) will retain the same quality and avoid any blurring.

When using PHP's GD, Drupal will make calls to imagecopyresampled which will affect image quality unless image width and height are kept the same or cropping is performed. This is partly due to imagecopyresampled and partly the way it is called. "Fastimagecopyresampled" is a possible replacement: (from http://us.php.net/manual/en/function.imagecopyresampled.php#77679) - this is a higher quality version of PHP's imagecopyresampled. It does result in higher quality but requires hacking Drupal code instead of overriding any hooks.

I've found that it's better to use ImageMagick than GD. The only remaining problem is that for similar quality images, the file size is something like twice as big after ImageMagick processing. You could mess around with ImageMagick's quality settings by hacking Image API code or by copying imageapi_imagemagick.module into a custom module and configuring it for use instead. But you risk breaking quality for other images. I haven't found the reason why IMagick makes image file sizes larger.

Today I spent the day hacking on the WordPress site for BarCampSaigon. I'm no expert on WordPress but trying to hack a theme with it makes me appreciate Drupal so much more. WordPress does have an "API" or at least some documented functions which are used internally which can also be used by developers but it's certainly not designed with developers in mind. Wordpress is great for bloggers. Drupal is great for developers and users who need something more than a blog will have to choose between working with Drupal or fighting against WordPress. :-)

Due to two recent conferences, BarCamp Hanoi and the opening of DrupalVietnam.org, I put together a presentation called "The Business Case for Drupal in Vietnam". I'll blog about those two events later.

I targeted two main groups: outsourcing companies based in Vietnam who want to attract more clients abroad, and any software development shop in Vietnam who is deciding what technology to use to develop websites. There is a third group, who are those companies with simpler website needs who perhaps only need one website and are not in the business of making websites.

I go over a number of common concerns that customers outside of Vietnam might have which Vietnamese companies might not expect. One point is being vendor agnostic when developing what is essentially a CMS. I make a strong point that one should never fall to the temptation of developing your own in-house CMS and as a consumer, you should stay far away from such "bespoke" solutions in the modern age where content management frameworks such as Drupal exist. I also think Drupal represents a strong brand name that is not well-known yet in Vietnam, but we all know how much Vietnamese people love brands.

On the supply side, I talk about why Drupal is a decent choice for Vietnamese developers, similar to any web developer. But the main recent news is that there is finally Drupal training being made available in Vietnam, much like for Joomla, and that PHP is widely known in Vietnam not just because there are books on it in the Vietnamese language, and that there is now a core Drupal community in Vietnam represented by DrupalVietnam.org (which I somehow became vice president of).

In general, I say go with your strengths. If web development is not your strength, then hire someone proper to do it for you while you focus on your core business. If web development is your business, make better use of your developers by using a CMS.

Anyways, here's the presentation.

Drupal Views hook_views_query_substitutions

Submitted by tomo on November 19, 2011 - 12:48am

Drupal's Views module has a lot of hooks that can be used to modify the behavior of a hook, from building the query to putting together the output. Hooks are also used by modules which want to add to the Views building interface, even the basic node-based Views.

Views supports a number of hooks which aren't documented. One I came across recently was hook_views_query_substitutions. This is potentially a powerful hook, one which the module Views arguments in filters (currently a sandbox module only for developers) takes advantage of to allow filter value substitution from the Views UI.

Hook hook_views_query_substitutions is pretty basic. By implementing the hook, you return an array of values you want to substitute with the keys you want to substitute for. This is how the magic values like ***ADMINISTER_NODES*** which you see in the Views query preview get turned into valid SQL.

For example:

function user_views_query_substitutions($view) {
  global $user;
  return array('***CURRENT_USER***' => intval($user->uid));
}

After this hook is called, Views will then run str_replace with the keys of the substitutions array and its values and apply it to the breadcrumb, title, and views arguments, as well as the query string that has been built so far.

Hook hook_views_query_substitutions gets called in the execute() call of Views. The first thing execute() does is build(), which you can hook into with hook_views_pre_build, hook_views_query_alter, and views_post_build (in that order), then you can hook into hook_views_pre_execute and hook_views_post_execute (the latter happens after the views query is executed and shows an unsubstituted query, there is no hook where one can see the substituted query). You also have a chance to hook into the db_rewrite_sql call.

Module "Views arguments in filters" is pretty basic and only allows substitution in filters which allow you to enter open text (so that you can set a value like '%1'). But by doing something similar, we can use a string passed in as a Null argument to command a Drupal module to do even more, like string substitution on any part of the query. I have a module in development now that does exactly that.

Saigon MobileDevCamp 2011

Submitted by tomo on November 8, 2011 - 2:16am

This past weekend was the third annual Saigon MobileDevCamp held at Bach Khoa University. Although I'm mainly a web developer, as the event was billed as a brother to BarCamp, I decided to go and check it out, meet some people, support my friend Dan, and see if anything from the event could be applied to the upcoming BarCamp Saigon on December 11th.

Like BarCamp, the venue is a local university. However, the quality of facilities between a regular Vietnamese university like Bach Khoa and a foreign-operated campus like RMIT are on a quite different level. Most rooms were without air conditioning and became quite hotter than I'm accustomed to. In the morning there were a number of sessions on developing mobile apps (I checked out a session on PhoneGap but missed the Unity 3D session). In contrast to the BarCamp ideal, guest speakers were invited to give sessions which were planned and scheduled beforehand. Topics were confined to the "mobile development" theme.

After lunch, the main event would be a 24-hour coding competition. As I was already waking up far earlier than usual to attend the conference which I hadn't even properly registered for, I had no intention of joining the hackathon but I would eventually be overcome by my friend Cong's excitement for Doing Things.

So that's it. We lost. We learned some lessons.

1. Be one of the first to present if you can.

2. Don't single out and alienate judges.

3. Don't build clean, well-architected software with maintainable code. In real life, this matters. For this competition, it doesn't.

The greatest tragedy perhaps (besides not winning) was that the presentations were all made in private with the judges. Having groups present their apps for everyone to see, or at least putting them somewhere online, would have been the BarCamp way. As we didn't receive any feedback or anything from the judges, it would have been nice to share what we all worked on for 24 hours (multiplied by nearly 100 people) and be able to learn from others' experience. Even if there wasn't time for all to present, I don't think I was the only one interested in seeing at least the demos from the winners.

Importing and Exporting Drupal Taxonomy

Submitted by tomo on August 31, 2011 - 3:10am

There are multiple modules for importing and exporting Drupal taxonomies (Drupal switches between using the term "taxonomy" and "vocabulary" like a clinical schizophrenic). Some use CSV format (http://drupal.org/project/taxonomy_csv), others XML (http://drupal.org/project/taxonomy_xml), and still others use a PHP array (http://drupal.org/project/taxonomy_export).

Some of these modules use the same paths for the export and import pages but they are different modules and aren't compatible. If you have both Taxonomy Export and Taxonomy XML installed at the same time they will conflict.

Except for CSV, the other import/export modules need you to create documents in a rather wordy XML or PHP code format, which can actually be more work than entering the terms in manually. Some people may use taxonomy import/export for only the taxonomy definition rather than terms. It's sometimes unclear what happens if you want to re-import duplicate term names later.

What worked best for me was using Taxonomy Manager which gives you an improved UI for organizing terms within a vocabulary. I wish it made editing the core fields of a taxonomy more ajax-y but what it does provide is an easy way to add multiple terms at once, a textarea for pasting in a list of terms, and a way to select where the new terms will go. So you can paste in all the top level terms, then paste in all the 2nd level children of the 1st term and select the 1st term to indicate they will all go under it. As long as you don't have too many different branches, then this can be done fairly easily.

[This blog post is a rewrite of just the main points due to my baby Macbook Pro dying while I was distracted.]

Drupal content types with CCK make it quite easy to add any number of defined fields to an 'object', and with multiple/unlimited values for a field or with node references it's possible to make a Drupal node 'two-dimensional'.

Sometimes you need more. Sometimes you want tabular data, a table, to be part of a node. If the table always has the same dimensions, and at least the same columns for each node, then the above can work through node references and views.

What if you want to add a different two-dimensional table to nodes of a content type, but without knowing the number or labels for the columns and rows beforehand.  For example, you might want to attach a pricing table to a node, with multiple products and multiple ways to price each product.  An example of that might be 5 t-shirt designs, where shirts are priced based on size and quantity ordered.

Read the rest of this article...

Drupal Views UI Filter Fields by Content Type

Submitted by tomo on April 21, 2011 - 4:18am

Late night hack:

You have a lot of fields in a lot of content types. You're creating a view with new display fields but it's a pain to find just the content type fields you want. Wouldn't it be cool if you could just select a content type from a pulldown and see content fields filtered to just the ones in that content type?

Add this bookmarklet to your bookmarks bar:
Views UI Filter

Read the rest of this article...

Drupal Add Comment Form Above Comments

Submitted by tomo on March 24, 2011 - 12:57am

Drupal 6 allows you to either display the comment form below saved comments or on a separate page. There's surprisingly no way to configure the form to appear above the comments. It's hard-coded at the bottom of comment_render to either append the form, or not at all.

There's a micro-module aptly titled 'Comment form above comments' which does the job but does so using string replaces on resulting html so it's not the ideal or elegant solution.

It turns out to be simple to get the same effect in code.

First, we need to "configure" the form to appear on a separate page, but only because we're going to manually show it. You can ensure this configuration with the line:

variable_set('comment_form_location_'.$node->type, COMMENT_FORM_SEPARATE_PAGE);

You could even variable_get and re-variable_set after printing the form if you really wanted to.

Next, output the following where you want to display comments, whether in a PHP code block or node template:

$edit = array('nid' => $node->nid);
print comment_form_box($edit) . comment_render($node);

Another recent discovery was that the comment form is hard-coded to redirect to /node after submitting. This hack, as a module, will get you back to the page you submitted from:

function noredirect_comment_form_submit(&$form, &$form_state) {
    $form_state['redirect'] = ltrim($form['#action'], '/');
}

function noredirect_form_alter(&$form, $form_state, $form_id) {
    if ($form_id == 'comment_form') {
       $form['#action'] = request_uri();
        $form['#submit'][] = 'noredirect_comment_form_submit';
    }
}

Syndicate content
© 2010-2014 Saigonist.