FavIcons, Apple Touch Icons, Site Thumbnail Images: PHP and WordPress Coding Issues
This is the third part of a three-part discussion of favicon
s, Apple-Touch icons, site thumbnail images, and how to tag pages (especially WordPress pages) to associate them with such graphics. The first part explained the purpose of these graphics, and the required HTML. The second part provides working code that can be dropped into a WordPress theme (specifically, into functions.php
). This final, very boring part motivates that code, and provides some more general discussion which could be applied to PHP other than WordPress.
In discussing the nature of favicon
s, Apple Touch icons, and thumbnail graphics used by linking sites, I tried to give some indication as to how I thought the HTML ought to be handled. Even in the case of dynamically generated webpages, some of the code that I've seen out there just hard-codes the HTML for these graphics. Such code is very breakable, as when, for example, a 'blog is relocated to a different directory (perhaps of a different domain). And, in the case of dynamically generated individual posts and pages which are to have their own thumbnail images, the handling too must be dynamic.
There are further issues in how generating PHP code should be designed, some general, and some specific to WordPress.
[Up-Date (2020:05/19): I up-dated the code to-day, but have only partially up-dated the discussion around the code. So the explanations are a bit crufty.]
General PHP Issues
From the perspective of user-friendliness, perhaps the best route would involve creäting a webpage interface that would allow the user to upload graphics files, and declare these or files already present to be the favicon
, Apple Touch icons, or default thumbnail graphic icons. For the aforementioned sorts of files, my code just looks for candidates from within restricted sets of names, and uses the first of each that it encounters. In the case of favicon
s and thumbnail images, the differences amongst allowed file names is to support different extensions, corresponding to different formats; but a single file-name could have been imposed, with no extension or with the extension ignored. In the case of Apple Touch icons, the names themselves pass further information to the client device interface.
The basic idea is just
$filespec = "";
if (file_exists("candidateNameFirst")
$filespec = $siteURL . "candidateNameFirst";
else if (file_exists("candidateNameSecond")
$filespec = $siteURL . "candidateNameSecond";
…
else if (file_exists("candidateNameLast")
$filespec = $siteURL . "candidateNameLast";
if ($filespec)
echo "<tagStuff" . $filespec . "moreTagStuff />\n";
for each sort of image (the favicon
, the Apple touch icons, and the default thumbnail images). The site URL isn't in the code as a (sub)string literal so that the user doesn't have to mess with it at each installation. The major complication is when the user has selected a distinct image file to be used as a thumbnail graphic for a particular page. That file then has to be invoked.
Some of the tags to be generated have a type
attribute, in which a MIME image type is supposed to be identified. The easiest way to infer an image type is from the file-name extension (eg
), but I've encountered many files of one sort with the extension of another. So my thinking was to call a function to identify the MIME type. I didn't find a standard function that did just that, but the ill-named jpg
getimagesize
function actually returns an array, one element of which (since PHP version 4.3.0) is MIME type information. So I could call getimagesize
within another function, which would just return that type information.
/* First Attempt */
function getimagemimetype ($filespec)
{
$imagesizearray = getimagesize($filespec);
return($imagesizearray['mime']);
}
Unfortunately, while I found that this worked fine for GIF, JPEG FIF, and PNG files, it returned an empty string for MS icon files. In cases where an empty string is returned, I resorted to reading the first four bytes of the file, and comparing these with the first four bytes of the MS icon file specification. (The comparison itself is somewhat kludgy, because PHP is not good about reading bytes as such nor about comparing characters in strings to integral values, and treats a byte 0x00
as an EOS).
function getimagemimetype ($filespec)
{
$imagesizearray = getimagesize($filespec);
$type = $imagesizearray['mime'];
if (strlen($type) == 0)
{ /* See if it might be a .ICO */
$identifier = fread(fopen($filespec,'r'),4);
$bytes = "\x0\x1\x2";
if ( ($identifier[0] == $bytes[0]) && ($identifier[1] == $bytes[0])
&&
(($identifier[2] == $bytes[1]) || ($identifier[2] == $bytes[2]))
&&
($identifier[3] == $bytes[0]))
$type = "image/vnd.microsoft.icon";
}
return ($type);
}
Hypothetically, I could have just punted to looking for a file-name extension of
exactly and only when .ico
getimagesize
failed, or even never invoked it for files with that extension. Also, the results of experimentation suggest that setting the type
attribute to an empty string will not prevent a MS icon from working as a favicon
.
Another possibility would be to read the first few bytes of any file, rather than calling getimagesize
. A GIF file begins
or GIF87a
and its proper MIME type is GIF89a
; a JPEG FIF file begins image/gif
(where \xFF\xD8\xFF\xE0\xdd\xddJFIF\x00
is some hexadecimal digit) and its proper MIME type is d
; an ICO file begins image/jpeg
or \x00\x00\0x00\0x01
and its proper MIME type is \x00\x00\0x00\0x02
; a PNG file begins image/vnd.microsoft.icon
and its proper MIME type is \x89PNG\x0D\x0A\x1A\x0A
. But (as noted parenthetically above) PHP is not good about handling the comparison in cases where a zero byte is part of the header; it might be best to provide a separate function to handle the byte comparisons as such, if there are going to be many of them.image/png
The code to identify MIME type could be put in-line everywhere it were used; but, unless it is going to be from bald acceptance of the file-name extension (in which case it might be done when the file existence were detected), there would be dubious efficiencies in doing that.
My code for the favicon
conforms pretty closely to the basic structure sketched above, but the MIME type is handled by introducing a variable $favicon_type
, set as part of the positive outcome of any condition.
if (file_exists("favicon.xxx"))
{
$favicon_spec = get_bloginfo('siteurl') . "/favicon.png";
$favicon_type = getimagemimetype("favicon.xxx");
}
(NB: The function get_bloginfo
is here drawn from WordPress.) My order of preëmption was fairly aribitrary.
My code for the AppleTouch icons actually just puts the echo
commands within the conditionals.
$siteurl = get_bloginfo('siteurl');
$apple_touch_icon_possible_size = array("57", "72", "76", "120", "144", "152", "180");
foreach ($apple_touch_icon_possible_size as $apple_touch_icon_size)
{
$apple_touch_icon_sizes = $apple_touch_icon_size . "x" . $apple_touch_icon_size;
$apple_touch_icon_name_partial = "apple-touch-icon-" . $apple_touch_icon_sizes;
if (file_exists($apple_touch_icon_name_partial . "-precomposed.png"))
echo " <link rel=\"apple-touch-icon-precomposed\" sizes=\"" . $apple_touch_icon_sizes . "\" href=\""
. $siteurl . $apple_touch_icon_name_partial . "-precomposed.png\" />\n";
else if (file_exists($apple_touch_icon_name_partial . ".png"))
echo " <link rel=\"apple-touch-icon\" sizes=\"" . $apple_touch_icon_sizes . "\" href=\"" . $siteurl
. $apple_touch_icon_name_partial . ".png\" />\n";
}
The order of preëmption conforms to what an standard client would do in the absence of tags.
My code for the thumbnail graphics is very much like that for the favicon
, except that it first looks for a page-specific image.
WordPress Issues
The first question is of what, if anything, to put in functions.php
and of what, if anything, to put in header.php
. In order to use the featured image
facility of WordPress version 2.9 and later, functions.php
must have
add_theme_support('post-thumbnails');
(preferably prefaced with
) inserted into it. All of the remaining code here could be put into either if (function_exists('add_theme_support'))
.php
file, though getimagemimetype
should probably be defined in functions.php
.
I chose to put everything remaining also into functions.php
. That meant wrapping it into one or more functions, and then adding each such function as an action
to wp_head
. If, instead, that code were placed in header.php
, then the code should be inserted somewhere within the head
element, and only the code of getimagemimetype
should be wrapped into a function. Given that the code is all being placed in functions.php
, the next question is of whether to put the code for all three sorts of graphics into just one function. If one is always going to use all of the functionality, and never modify the implementation once it's effected, then one function is fine. But, for ease of maintainability, I chose to creäte three functions, one for each basic sort of graphic; that required three calls to add_action
, one for each of those functions.
I've seen code for the thumbnail graphic that provides a default for
pages (individual entries, and those pages which WordPress calls singular
Pages
) that do not have a Featured Image, but that does not provide thumbnails for non-singular
pages. I don't see why the default thumbnail graphic should not be used in such cases. In any event, the code for extracting the page-specific thumbnail specification is a bit rococco.
if (is_singular())
if (function_exists('has_post_thumbnail'))
if (has_post_thumbnail())
{
$image_array = wp_get_attachment_image_src(get_post_thumbnail_id());
$thumbnail_graphic_spec = esc_attr($image_array[0]);
}
get_post_thumbnail_id
(with no argument) returns an integer associated with the featured image for the present page. Basically by look-up, wp_get_attachment_image_src
converts that integer into an array, the initial element of which is a URL for the featured image. esc_attr
makes sure that characters that could cause awkwardness are removed or escaped.