Go to main content

Textpattern CMS support forum

You are not logged in. Register | Login | Help

#16 2010-12-03 19:14:59

jsoo
Plugin Author
From: NC, USA
Registered: 2004-11-15
Posts: 1,793
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Having looked at this code several times, I can’t help but make a few more comments:

  • The resize() operation is best done after you’ve decided which image to use, so that you only do it once. Not a big deal as resize() appears to have a cache, but as a general point you don’t want to run a big function more than necessary.
  • Best not to include non-core functions (resize()) without giving them a distinct prefix, as with plugins.
  • The first matching pattern assumes any img tag to be a flickr embed. Pretty big assumption.
  • If you know you are in article context you can use permlinkurl($GLOBALS['thisarticle']) to generate the link URL. It would automatically use the permanent link mode set in site prefs, and would allow you to delete several lines of code. For that matter, you could use permlink() function to generate the anchor tag as well, if you don’t mind rel="bookmark" as a tag attribute. Again, you can wait to do this after you’ve decided which image to use.
  • You can get rid of the // Edit: see below comments I added :)

Code is topiary

Offline

#17 2010-12-03 21:39:15

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

jsoo thanks for the tips and suggestions. I’m shaky with PHP, but I think I’ve managed to clean it up a bit while keeping it working.

<txp:php>
  if (preg_match('@^([\s\S]*?)<img src=([^<]+)/>@',$thisarticle['body'], $matches)) 
  {
	$first_bodyimg = strlen($matches[1]);
	$bodyimg = explode(" ",$matches[2]);
}
if (preg_match('#^([\s\S]*?)<object[^>]+>.+?http://www.youtube.com/v/([A-Za-z0-9\-_]+).+?</object>#s', $thisarticle['body'], $matches))
  {
	$first_youtube = strlen($matches[1]);
	$youtubeid = $matches[2];
}
if (isset($bodimg) and isset($youtube))
	echo $first_bodimg < $first_youtube ? $bodyimg : $youtubeid;
elseif (isset($bodyimg)) {
	$imgurl = trim($bodyimg[0],"\"");
	$thumbsized = resize("$imgurl",array("w"=>200));
	$arturl = permlinkurl($GLOBALS['thisarticle']);
	echo "<a href=\"".$arturl."\" /><img src=\".".$thumbsized."\" /></a>";
}
elseif (isset($youtubeid)) {
	$thumbsized = resize('http://i.ytimg.com/vi/'.$youtubeid.'/0.jpg',array('w'=>200));
	$arturl = permlinkurl($GLOBALS['thisarticle']);
	echo "<a href=\"".$arturl."\" /><img src=\".".$thumbsized."\" /></a>";
}
</txp:php>

I can’t figure out how to use the permlink() function, but permlinkurl($GLOBALS['thisarticle']) is working fine.

Re: resize(): should I add a prefix like img_resize()? I’m really naive when it comes to plugin/core protocol. I guess I would need to add the prefix to the native resize code (it is in a separate file on the server).

And finally, a quick question about the s that comes after the # sign in the preg_match line for finding YouTube videos. I removed the s at some point while playing around with your code. With or without the s, everything seems to work fine. Does it play an important role? I went ahead and put it back in the code above just to be safe.

Again, thanks so much for all of your help and suggestions!!

Offline

#18 2010-12-04 01:16:55

jsoo
Plugin Author
From: NC, USA
Registered: 2004-11-15
Posts: 1,793
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Just about. However, your latest revision won’t work correctly if the article contains both types of content.

Here’s what I had in mind:

<txp:php> 

// Regex patterns to search for embedded flickr and youtube content
	$img_pattern = '#^(.*?)<img src=(\'|")(.+?)\2#s';
	$youtube_pattern = '#^(.*?)<object[^>]+>.+?http://www.youtube.com/v/([A-Za-z0-9\-_]+).+?</object>#s';

// Check for embedded content; if found calculate position from start of article
	$first_bodyimg = preg_match($img_pattern, $thisarticle['body'], $img_match) ? 
		strlen($img_match[1]) : null;
	$first_youtube = preg_match($youtube_pattern, $thisarticle['body'], $youtube_match) ?
		strlen($youtube_match[1]) : null;

// Resize and output thumbnail for first embedded content
	if ( $first_youtube and ( is_null($first_bodyimg) or $first_youtube < $first_bodyimg ) )
		echo permlink(array(), resize('http://i.ytimg.com/vi/'.$youtube_match[2].'/0.jpg',array('w'=>200)));
	elseif ( $first_bodyimg and ( is_null($first_youtube) or $first_bodyimg < $first_youtube ) )
		echo permlink(array(), resize($img_match[3], array("w"=>200)));

</txp:php>

I’ve tweaked the flickr regex pattern so it uses the same delimiters (the # characters) as the youtube pattern, and I’ve added back the s after both patterns — this is a regex option that allows the . in the pattern to also match line returns (so I can do away with [\s\S]). I added an extra subpattern (the (\'|")) to the flickr pattern so that $youtube_match[3] will capture just the image URL, so I can eliminate some extra steps. FYI, learning at least basic regex is quite handy even for non-coders. An increasing number of apps support regex in find and replace dialogs, and you can do some real power editing with it.

There are more compact ways to format this code, but this version is clearer to read and maintain.

The resize() function is OK as named for now, because Txp does not have a function with the same name. Best practice is to use a distinct prefix for non-Txp functions to prevent that sort of conflict, so to be on the safe side you could rename the function photonomad_resize() (both in the function definition and in the function calls).


Code is topiary

Offline

#19 2010-12-04 18:52:34

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Wow, this is quite a revision! I had completely missed the problem in my version. Thanks for pointing that out! It reared its head when a youtube video came before an image in an article.

Ok, so there is only one issue in your new version that I can’t fix. The resize script only produces a url, not the full html img tag. I’ve messed around with it and can’t figure out how/where in the script to work the image tag in without adding a bunch more lines and eliminating the permlink() function.

Last edited by photonomad (2010-12-04 19:53:23)

Offline

#20 2010-12-04 19:52:44

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

I take that back, I got it working with the img tag. My first attempts involved some careless typos!

I changed this:

echo permlink(array(), resize('http://i.ytimg.com/vi/'.$youtube_match[2].'/0.jpg',array('w'=>200)));

to this:

echo permlink(array(), "<img src=\"".resize('http://i.ytimg.com/vi/'.$youtube_match[2].'/0.jpg',array('w'=>200))."\" />");

and this:

echo permlink(array(), resize($img_match[3], array("w"=>200)));

to this:

echo permlink(array(), "<img src=\"".resize($img_match[3], array("w"=>200))."\" />");

Thanks again!!

Offline

#21 2010-12-04 20:25:20

jsoo
Plugin Author
From: NC, USA
Registered: 2004-11-15
Posts: 1,793
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Good job. I was just previewing this post when you posted your latest, so here’s another way the code could be arranged:

// Check article body for embedded flickr and/or youtube content
	$img_pattern = '#^(.*)<img src=(\'|")(.+flickr\.com.+)\2#sU';
	$youtube_pattern = '#^(.*)<object.+youtube\.com/v/([\w-]+).+</object>#sU';

// Check for embedded content; if found calculate position from start of article
	$first_bodyimg = preg_match($img_pattern, $thisarticle['body'], $img_match) ? 
		strlen($img_match[1]) : null;
	$first_youtube = preg_match($youtube_pattern, $thisarticle['body'], $youtube_match) ?
		strlen($youtube_match[1]) : null;

// Find first instance and resize it
	$img_src = null;
	if ( $first_youtube and ( is_null($first_bodyimg) or $first_youtube < $first_bodyimg ) )
		$img_src = resize('http://i.ytimg.com/vi/'.$youtube_match[2].'/0.jpg',array('w'=>200));
	elseif ( $first_bodyimg and ( is_null($first_youtube) or $first_bodyimg < $first_youtube ) )
		$img_src = resize($img_match[3], array("w"=>200));

// If we have an image src, output the image as the contents of a link to the current article
	if ( $img_src )
		echo permlink(array('class'=>'article-thumb'), '<img src="'.$img_src.'" alt="" />');

Among other things this avoids repeating the permlink() code, including the concatenated strings for building the img tag. Not a big deal, but if you wanted to add, say, a title attribute to the img tag, there’s only one place you need to edit.

Note that I’ve added a class attribute to permlink(). When calling a Txp tag directly as a PHP function, the first argument is always the tag attribute array.

I also made a few tweaks to the regex patterns. I added the U option to both patterns. This makes the * and + quantifiers non-greedy by default, so I can do away with the ? modifiers. I added flickr\.com to the flickr pattern to only match flickr images. I removed the http./ from the youtube pattern because it doesn’t really add anything useful. I changed the [A-Za-z0-9\-_] character class to [\w-], which is identical. I escaped the literal dot characters (youtube\.com), because an unescaped dot in regex matches any character.


Code is topiary

Offline

#22 2011-04-07 20:22:00

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Hello! I have another php/regex question. It appears that YouTube recently changed the format of the code for embedding videos. Instead of an <object>, they are now using an <iframe> and the video id comes after embed/ in the src.

Example:

<iframe title="YouTube video player" width="480" height="390" src="http://www.youtube.com/embed/9JA0QVP3JwQ" frameborder="0" allowfullscreen></iframe>

I need help understanding how to modify the script so that it will look for the first object or iframe with youtube code.

Also, jsoo, I decided that I do not want to limit the script for just Flickr images. I tried to modify your changes (so that it would find any img tags) in the revised code (in your post above) and I wasn’t able to get it to work correctly.

I have been using the following:

<txp:php> 
// Regex patterns to search for embedded image and youtube content
	$img_pattern = '#^(.*?)<img src=(\'|")(.+?)\2#s';
	$youtube_pattern = '#^(.*?)<object[^>]+>.+?http://www.youtube.com/v/([A-Za-z0-9\-_]+).+?</object>#s';

// Check for embedded content; if found calculate position from start of article $first_bodyimg = preg_match($img_pattern, $thisarticle[‘body’], $img_match) ? strlen($img_match1) : null; $first_youtube = preg_match($youtube_pattern, $thisarticle[‘body’], $youtube_match) ? strlen($youtube_match1) : null;

// Resize and output thumbnail for first embedded content if ( $first_youtube and ( is_null($first_bodyimg) or $first_youtube < $first_bodyimg ) ) echo permlink(array(), “<img src=\”.”.resize(‘http://i.ytimg.com/vi/’.$youtube_match2.’/0.jpg’,array(‘w’=>150)).”\” />”); elseif ( $first_bodyimg and ( is_null($first_youtube) or $first_bodyimg < $first_youtube ) ) echo permlink(array(), “<img src=\”.”.resize($img_match3, array(“w”=>150)).”\” />”);
</txp:php>

Offline

#23 2011-04-08 13:46:49

jsoo
Plugin Author
From: NC, USA
Registered: 2004-11-15
Posts: 1,793
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

photonomad wrote:

$img_pattern = '#^(.*?)<img src=(\'|")(.+?)\2#s';

Should still be OK for matching the first img tag. This might improve it, in case of tags in which src is not the first attribute:

$img_pattern = '#^(.*?)<img\s[^>]*src=(\'|")(.+?)\2#s';

photonomad wrote:

$youtube_pattern = '#^(.*?)<object[^>]+>.+?http://www.youtube.com/v/([A-Za-z0-9\-_]+).+?</object>#s';

Untested, but this might work if you need to test for either object or iframe:

$youtube_pattern = '#^(.*?)<(object|iframe)[^>]+>.+?http://www.youtube.com/(?:v|embed)/([A-Za-z0-9\-_]+).+?</\2>#s';

With this latter pattern there is an extra matching subpattern (the (object|iframe) subpattern), so you would need to change this in the $youtube_match index for the ID (i.e., use $youtube_match[3]).


Code is topiary

Offline

#24 2011-04-09 19:32:11

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Hi jsoo, Thanks for your help!

I’ve tested it and the new image pattern works great and finds the src no matter what order it appears in the <img> tag!

The youtube regex pattern works fine too, but I’m getting stuck with the $youtube_match index. You are correct, $youtube_match[2] does not work. The resize script runs, but doesn’t return an actual image url.

When I switch $youtube_match[2] to $youtube_match[3], it works, but does not return the first occurrence. If there is only one youtube (object and/or iframe) in the article body, then no image is returned. When I put two youtube (objects and/or iframes) in the same article, the second video’s image is returned. If I put an image in between two youtubes, the second youtube is returned and the still image is ignored. However, if there is a youtube first and then an image and no other youtubes, then the still image is returned. I am stumped as to how to fix it. Any ideas?

Thanks so much!

Offline

#25 2011-04-09 20:30:45

jsoo
Plugin Author
From: NC, USA
Registered: 2004-11-15
Posts: 1,793
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Right. I was trying to avoid needing a third pattern, but I overlooked the fact that iframe is all one element. Probably best to add in a third pattern.

$img_pattern = '#^(.*?)<img\s[^>]*src=(\'|")(.+?)\2#s';
$iframe_pattern = '#^(.*?)<iframe[^>]+http://www.youtube.com/embed/([A-Za-z0-9\-_]+)#s';
$object_pattern = '#^(.*?)<object.+?>.+?http://www.youtube.com/v/([A-Za-z0-9\-_]+).+?</object>#s';

Determining which comes first is trickier. There’s probably a cleaner way to do this, but this should work:

if ( $first_img )
{
	if ( $first_iframe )
	{
		if ( $first_iframe < $first_img )
			$first_img = null;
		else
			$first_iframe = null;
	}
	if ( $first_object )
	{
		if ( $first_object < $first_img )
			$first_img = null;
		else
			$first_object = null;
	}
}
if ( $first_iframe && $first_object )
{
	if ( $first_iframe < $first_object )
		$first_object = null;
	else
		$first_iframe = null;
}

Then something like:

if ( $first_img ) echo ...
if ($first_iframe) echo ...
if ($first_object) echo ...

Code is topiary

Offline

#26 2012-07-30 02:35:31

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Hello! I am revisiting this code and was wondering how I can make the results into a variable? Something like: <txp:variable name=“bodyimg” /> I want to be to test if there are any embedded images in the article body, then output different code in my article form if there aren’t.

Scratch the above. I have bigger issues now because I’m using hak_tinymce to insert images into the body of articles. If the appearance of an image is edited when inserting an image into an article, the style tag shows up between <img and src=”, like this: <img style=“float:left;” src=”. The regex code for finding images doesn’t work (see posts in this thread above for sample code of regex pattern). I’m starting to wonder if I need to use something other than regex to find the first image or video? Or, is there some regex that will find the src regardless of the attribute order? I’ve searched the web for regex patterns, but can’t find any that work here. I know it isn’t the ideal situation for regex, but I’m not sure how else to proceed. Anyone have advice? Thanks.

Last edited by photonomad (2012-07-30 04:49:24)

Offline

#27 2012-07-30 14:32:42

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

I found a solution. :) Inspired by this post on Stackoverflow, I gave phpQuery a try. The code below works great for finding the first image src in an article body and storing it as a variable. (I am postponing the youtube test for now).

Call at top of page: <txp:php>require 'phpQuery-onefile.php';</txp:php>

<txp:php>
global $variable;
$texthtml = $thisarticle['body']; 
$pq = phpQuery::newDocumentHTML($texthtml);
$img = $pq->find('img:first');
$src = $img->attr('src');
$variable['bodyimg'] = $src;
</txp:php>

<txp:if_variable name="bodyimg" value="">nope<txp:else /><txp:variable name="bodyimg" /></txp:if_variable>

My next challenge is to introduce the logic of finding the first youtube video id or first img src, whichever comes first in the article body.

Offline

#28 2012-07-31 21:01:59

etc
Developer
Registered: 2010-11-11
Posts: 5,674
Website GitHub

Re: Article thumbnail image from YouTube/Flickr code found in Body

You could give a try to etc_query:

<txp:variable name= "bodyimg" value='<txp:etc_query data="{?body}" query="//img[1]@src?" />' />

Offline

#29 2012-08-01 17:16:41

photonomad
Member
Registered: 2005-09-10
Posts: 290
Website

Re: Article thumbnail image from YouTube/Flickr code found in Body

Thanks, etc! I’m trying out your plugin now and there is a problem somewhere (using the txp:variable code you included in the post above). I’m not sure how to fix it:

Tag error: <txp:etc_query data=”{?body}” query=”//img1@src?” /> -> Warning: DOMXPath::evaluate() [domxpath.evaluate]: Invalid expression on line 194
textpattern/lib/txplib_misc.php(653) : eval()’d code:194 DOMXPath->evaluate()
textpattern/publish.php:1188 etc_query()
textpattern/publish.php:1100 processTags()
textpattern/lib/txplib_misc.php:1053 parse()
textpattern/publish.php:1188 splat()
textpattern/publish.php:1100 processTags()
textpattern/publish.php:847 parse()
textpattern/publish.php:964 doArticles()
textpattern/publish.php:954 parseArticles()
textpattern/publish.php:1188 article_custom()

Offline

#30 2012-08-01 19:03:19

etc
Developer
Registered: 2010-11-11
Posts: 5,674
Website GitHub

Re: Article thumbnail image from YouTube/Flickr code found in Body

Yes, sorry, should be <txp:etc_query data="{?body}" query="//img[1]/@src">{?}</txp:etc_query>.

Edit: or <txp:etc_query data="{?body}" query="string(//img[1]/@src)" />

Last edited by etc (2012-08-01 19:09:03)

Offline

Board footer

Powered by FluxBB