I've got a weird layout to get around and am at a loss, even in the planning stage. Essentially I need to separate out all content that's not a .gallery and put it into an <aside />. I initially considered a plugin using the edit_post hook from the Plugin API, but have since decided against it because this content change is layout specific and I want to maintain a clean database. So...
How can I parse through WP's the_content for content that's not .gallery? Admittedly not a PHP guy, so I doubly appreciate the help!
As per Michael's comment below - here's an example of WP's the_content class output:
HTML
<div class="entry-content">
<div class="gallery">
<dl class="gallery-item">
<dt class="gallery-icon portrait">
<img src="/imagePath/etc.jpg" class="attachment-thumbnail">
</dt>
</dl>
<dl class="gallery-item">
<dt class="gallery-icon portrait">
<img src="/imagePath/etc.jpg" class="attachment-thumbnail">
</dt>
</dl>
<dl class="gallery-item">
<dt class="gallery-icon portrait">
<img src="/imagePath/etc.jpg" class="attachment-thumbnail">
</dt>
</dl>
</div>
<p>Curabitur vulputate, ligula lacinia scelerisque tempor, lacus lacus ornare ante, ac egestas est urna sit amet arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed molestie augue sit amet.</p>
<ul>
<li>Item A</li>
<li>Item B</li>
<li>Item C</li>
</ul>
</div>
Desired Output
<div class="entry-content">
<div class="gallery">
<dl class="gallery-item">
<dt class="gallery-icon portrait">
<img src="/imagePath/etc.jpg" class="attachment-thumbnail">
</dt>
</dl>
<dl class="gallery-item">
<dt class="gallery-icon portrait">
<img src="/imagePath/etc.jpg" class="attachment-thumbnail">
</dt>
</dl>
<dl class="gallery-item">
<dt class="gallery-icon portrait">
<img src="/imagePath/etc.jpg" class="attachment-thumbnail">
</dt>
</dl>
</div>
<aside>
<p>Curabitur vulputate, ligula lacinia scelerisque tempor, lacus lacus ornare ante, ac egestas est urna sit amet arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed molestie augue sit amet.</p>
<ul>
<li>Item A</li>
<li>Item B</li>
<li>Item C</li>
</ul>
</aside>
</div>
You'll want to use a Dom Parser for this. Here's an example in how you can go about it using your markup as an example. Testing yielded the desired results, so hopefully this will give you the head start you need:
add_filter( 'the_content', 'wrap_nongallery_aside', 20 );
function wrap_nongallery_aside($content){
$dom = new DOMDocument();
$dom->loadHTML($content); // Replace with Edit below if PHP >= 5.4
$aside = $dom->createElement('aside');
$xpath = new DOMXPath($dom);
$not_gallery = $xpath->query('//div[#class="entry-content"]/*[not(contains(#class, "gallery"))]');
foreach($not_gallery as $ng){
$aside->appendChild($ng);
}
$dom->getElementsByTagName('div')->item(0)->appendChild($aside);
return $dom->saveHTML();
}
Edit:
If you're using PHP >= 5.4, then you can easily remove any extra <html> and <body> tags from the generated markup by using the following:
$dom->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
Maiorano84's answer worked beautifully, but prior to his reply I worked out an alternate method that's less specific to my situation, so I figured it'd be good to share.
I had originally written off the plugin approach because it requires changing post content itself - not just the format of the output, but realized that plugins live independent of the theme installation. Below is a very simple, developer targeted plugin that converts a [aside /] shortcodes into HTML elements. It's entirely based on BSD Aside by Sean D Burkin. I'll eventually include a button for the WP text editor and open source it.
<?php
/*
Plugin Name: RW Content Aside
Description: Inserts aside formatting into post content via shortcodes
Author: Daniel Redwood
Version: 0.1
Author URI: http://www.rdwd.fm/
Based on SBD Aside by Sean B. Durkin:
Original Plugin: http://seanbdurkin.id.au/pascaliburnus2/archives/51
Author: http://www.seanbdurkin.id.au
*/
if ( !is_admin() ){
add_filter('the_content', 'handle_rw_aside');
}
function generate_random_str( $length=10)
{
return substr(md5(rand()), 0, $length);
}
function generate_place_marker()
{
return '#' . generate_random_str( 10) . '#';
}
function GetBody( $aside_instruction) {
return preg_replace( '~^((<p>)? \S+\s*=\s*.*?(<br \/>|<\/p>)\n?)*~mi', '', $aside_instruction);
}
function handle_rw_aside($the_content)
{
$begin = generate_place_marker();
$end = generate_place_marker();
$new_content = preg_replace(
'~^((<p>)?\[aside\](<br />|</p>))(.*?)(^(<p>)?\[\/aside\](<br />|</p>))~ms',
$begin . '$4' . $end,
$the_content);
$new_content = preg_replace_callback(
'~^(<p>)?(!+\[\/?aside\])~m',
function ($match) {
return $match[1] . substr( $match[2], 1);
},
$new_content);
$pattern = '~'.$begin.'(.*?)'.$end.'~s';
return preg_replace_callback(
$pattern,
function ($match) {
$aside_instruction = $match[1];
$body = GetBody( $aside_instruction);
$aside = '<aside class="contentAside">' . $body . '</aside>';
return $aside;
},
$new_content);
}
?>
Related
Hey i want to display some html/css depending on how many rows there are in database basically. Is there a way to do this without echo? Because i'm lost when i have to use many ' '. Here is code sample
<?php foreach ($result as $row) {
}?>
<div id="abox">
<div class="abox-top">
Order x
</div>
<div class="abox-panel">
<p>lorem ipsum</p>
</div>
<br>
<div class="abox-top">
lorem</div>
<div class="abox-panel">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut ac convallis diam, vitae rhoncus enim. Proin eu turpis at ligula posuere condimentum nec eu massa. Donec porta tellus ante, non semper risus sagittis at. Pellentesque sollicitudin sodales fringilla. Ut efficitur urna eget arcu luctus lobortis. Proin ut tellus non lacus dapibus vehicula non sit amet ante. Ut nibh justo, posuere sit amet fringilla eget, aliquam mattis urna.</p>
</div>
There's nothing complicated about it:
Simple/ugly:
<?php while($row = fetch()) { ?>
<div>
<?php echo $row['somefield'] ?>
</div>
<? } ?>
Alternative:
<?php
while ($row = fetch()) {
echo <<<EOL
<div>
{$row['somefield']}
</div>
EOL;
}
and then of course there's any number of templating systems, which claim to separate logic from display, and then litter the display with their OWN logic system anyways.
you can simply use <?= short opening tag introduced in php 5.3 before PHP 5.4.0 came out you had to enable short_open_tag ini but after 5.4.0 tag
here is an example
<?php $var='hello, world'; ?>
<?=$var ?> // outputs world
hope it helps.
Templates engines makes your life a pie
Take Smarty for example, it's pretty good template library. What template engine does is fetch variables to pre defined templates.
Your code in simple php:
<?php
echo 'My name is '. $name. ', that's why I'm awesome <br>';
foreach ($data as $value) {
echo $value['name'].' is awesome to!';
}
?>
Code in smarty:
My name is {$name}, that's why I'm awesome <br>
{foreach $data as $value}
{$value} is awesome to!
{/foreach}
Template engines pros:
Templates are held in separate custom named files. (i.e users.tpl, registration.tpl etc)
Smarty Caches your views (templates).
Simple to use i.e {$views + ($viewsToday/$ratio)}.
A lot of helpers.
You can create custom plugins/functions.
Easy to use and debug.
Most importantly: It separates your php code from html!
Template engines cons:
Sometimes hard to grip the concept of working for beginner.
Don't know any more actually
When I dont want to use a template engine (I like Twig, btw), I do something like this:
1) Write a separate file with the html code and some custom tags where data should be presented:
file "row_template.html":
<div class="abox-top">{{ TOP }}</div>
<div class="abox-panel"><p>{{ PANEL }}</p></div>
2) And then, read that file and do the replacements in the loop:
$row_template = file_get_contents('row_template.html');
foreach ($result as $row) {
$replaces = array(
'{{ TOP }}' => $row['top'],
'{{ PANEL }}' => $row['panel']
);
print str_replace(
array_keys($replaces),
array_values($replaces),
$row_template
);
}
In addition, you can change the content of "row_template.html" without touching the php code.
Clean and nice to the eye!
I'm trying to scrape product descriptions on a div based on its id. If the description is too long it shows a "show more". The div id's are short-description and long description.
My code works great on short-description but invisible to the DOM parser for long-description. How can I toggle the show more and then call the long-description ?
function my_function($str){
$url = $str;
// break apart ugly affiliate URL
list($chuck, $keep) = explode('=', $url);
// call simple DOM library
require_once 'libs/simple_html_dom.php';
// clean up unencoded URL
$keep = preg_replace("/%u([0-9a-f]{3,4})/i","&#x\\1;",urldecode($keep));
// Get HTML from clean URL
$html = file_get_html($keep);
//find div element
foreach($html->find('*/div[id="short-description"]') as $element){
echo $element;
}
}
Content I'm trying to get.
<div id='short-description'>
Eos inciderint interpretaris ea. Eam ut legere aperiri qualisque.
In propriae perfecto gubergren vix. Omnesque perpetua id duo,
no mel habeo appetere persecuti. Dico phaedrum qui ad, discere euripidis
delicatissimi vim cu.....
<a class='more'>Show More</a>
</div>
<div id='long-description' style='display: none;'>
Eos inciderint interpretaris ea. Eam ut legere aperiri
qualisque. In propriae perfecto gubergren vix. Omnesque
perpetua id duo, no mel habeo appetere persecuti. Dico phaedrum
qui ad, discere euripidis delicatissimi vim cu.Eos inciderint
interpretaris ea. Eam ut legere aperiri qualisque.
<a class='less'>Show Less</a>
</div>
</div>
Update: Solved
Code was working the entire time, didn't realize the raw output had the tags attached. It was including
style='display: none;
so I couldn't see my output result. I added
echo strip_tags($element);
and then I could see the output.
Note: I'm using Wordpress, but I don't believe it's relevant to the answer, so I've asked it on SO. If I'm wrong, please tell me/move the question.
Okay, I'm loading up blocks of rich content (via Wordpress) which frequently contain many images wrapped in anchor tags. I'd like to step through all of them in order to display them as a tags with their relevant imgs inside.
I've already found this handy bit of regex-powered code which gets me the images perfectly well:
// Get the all post content in a variable
$posttext = $post->post_content;
//$posttext1 = get_cleaned_excerpt();
// We will search for the src="" in the post content
$regular_expression = '~src="[^"]*"~';
$regular_expression1 = '~<img [^\>]*\ />~';
// WE will grab all the images from the post in an array $allpics using preg_match_all
preg_match_all( $regular_expression, $posttext, $allpics );
// Count the number of images found.
$NumberOfPics = count($allpics[0]);
// This time we replace/remove the images from the content
$only_post_text = preg_replace( $regular_expression1, '' , $posttext1);
/*Only text will be printed*/
// Check to see if we have at least 1 image
if ( $NumberOfPics > 0 )
{
$this_post_id = get_the_ID();
for ( $i=0; $i < $NumberOfPics ; $i++ )
{ $str1=$allpics[0][$i];
$str1=trim($str1);
$len=strlen($str1);
$imgpath=substr_replace(substr($str1,5,$len),"",-1);
$theImageSrc = $imgpath;
global $blog_id;
if (isset($blog_id) && $blog_id > 0) {
$imageParts = explode('/files/', $theImageSrc);
if (isset($imageParts[1])) {
$theImageSrc = '/blogs.dir/' . $blog_id . '/files/' . $imageParts[1];
}
}
?>
<img class="alignleft" src='<?php echo get_bloginfo('template_directory').'/timthumb.php?src=' . $theImageSrc . '&h=150&w=150'; ?>' height="150" width="150" alt=""/>
I'd really like to wrap that bottom img with the relevant parent a. Any help here would be greatly appreciated.
An example of the content to be searched might be:
<h5>
<a href="http://www.example.com/imagefoo.jpg">
<img class="size-thumbnail wp-image-4091 alignleft" src="http://www.example.com/imagefoo-150x150.jpg" alt="" width="150" height="150" />
</a>
</h5>
<h5>
<a href="http://www.example.com/Image-Bar.jpg">
<img class="wp-image-4087 alignleft" title="Image - Bar" src="http://www.example.com/Image-Bar-150x150.jpg" alt="" width="150" height="150" />
</a>
</h5>
<h5>
<a href="http://www.example.com/Image-Alphe.jpg">
<img class="wp-image-4090 alignleft" title="Image-Alpha" src="http://www.example.com/Image-Alpha-150x150.jpg" alt="" width="150" height="150" />
</a>
</h5>
<img class="size-thumbnail wp-image-4088 alignleft" title="EXAMPLE-image-150" src="http://www.example.com/EXAMPLE-image-150-150x150.jpg" alt="" width="150" height="150" />
<h5>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</h5>
<a href="http://www.example.com/insanely-long-permalink-created-as-if-by-a-madman-who-knows-no-bounds-of-shame/" rel="attachment wp-att-2780">
<img class="alignright size-thumbnail wp-image-2780" title="Exhibition Title: Image Name by Artist Person" src="http://www.example.com/wp-content/uploads/2011/12/ExtraordinaryImage-150x150.jpg" alt="Example UK | Exhibition: Image by Artist Person" width="150" height="150" />
</a>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
EDIT: Here's the working code based on my needs. It uses XPath, based on cHao's answer below. (For what it's worth, I found Tizag's webpage very useful as an XPath primer, alongside this EarthInfo page.):
// Get the all post content in a variable
$posttext = $post->post_content;
$document = DOMDocument::loadHTML($posttext);
$xpath = new DOMXPath($document);
$i = 0;
# for each link that has an image inside it, set its href equal to
# the image's src.
foreach ($xpath->query('//a/img/..') as $link) :
$img = $link->getElementsByTagName('img')->item(0);
$link_src = $link->getAttribute('href');
$link_title = $link->getAttribute('title');
$img_src = $img->getAttribute('src');
$theImageSrc = $img_src;
global $blog_id;
if (isset($blog_id) && $blog_id > 0) {
$imageParts = explode('/files/', $theImageSrc);
if (isset($imageParts[1])) {
$theImageSrc = '/blogs.dir/' . $blog_id . '/files/' . $imageParts[1];
}
}
?>
<a href="<?php echo $link_src; ?>" rel="lightbox[<?php echo $this_post_id; ?>]" title="<?php if ($link_title) {
echo $link_title;
} else { the_title(); } ?>" class="cboxElement">
<img class="alignleft" src='<?php echo get_bloginfo('template_directory').'/timthumb.php?src=' . $theImageSrc . '&h=150&w=150'; ?>' height="150" width="150" alt=""/>
</a>
<?php
endforeach;
?>
You'd be better off not trying to use regular expressions for finding the images. They suck at parsing HTML.
Instead, check out the DOMDocument and DOMXPath classes.
$document = DOMDocument::loadHTML($posttext);
$xpath = new DOMXPath($document);
# for each link that has an image inside it, set its href equal to
# the image's src.
foreach ($xpath->query('//a[/img]') as $link) {
$img = $link->getElementsByTagName('img')->item(0);
$src = $img->getAttribute('src');
# do your mangling of $src here, resulting in $href.
# for example...
$href = preg_replace('/-\d+x\d+(?=\.[^.]*$)/', '', $src);
$link->setAttribute('href', $href);
}
$fixed_html = $document->saveHTML();
I have a lot of these in a file jQuery1332199407617="01" that need removing, however, the bunch of numbers of always different, is that any way I can just deleted everything between jQuery and ="(number is also always different)"?
Thanks in advance.
Sample of part of the file as requested:
(as you can see it adds another jQuery thing each time it is saved.. hence the need to remove it)
<H2 editing="false" revert="Projects:" jQuery1332198888840="12" jQuery1332199361841="12" jQuery1332199407617="12">ProjectsTesting</H2>
<UL class=list1 jQuery1332198888840="17" jQuery1332199361841="17" jQuery1332199407617="17">
<LI jQuery1332198888840="16" jQuery1332199361841="16" jQuery1332199407617="16">Praesent vestibulum molestie
<LI jQuery1332198888840="19" jQuery1332199361841="19" jQuery1332199407617="19">Aenean nonummy
<LI jQuery1332198888840="21" jQuery1332199361841="21" jQuery1332199407617="21">Hendrerit mauris phasellus
<LI jQuery1332198888840="23" jQuery1332199361841="23" jQuery1332199407617="23">Porta fusce suscipit varius
<LI jQuery1332198888840="25" jQuery1332199361841="25" jQuery1332199407617="25">Cum sociis natoque
<LI jQuery1332198888840="27" jQuery1332199361841="27" jQuery1332199407617="27">Penatibus et magnis disI
<LI jQuery1332198888840="29" jQuery1332199361841="29" jQuery1332199407617="29">Parturient montes </LI></UL></DIV>
This will remove the jQuery text, no matter what numbers are present. It will also take out the excessive space at the end of the tags which is left after the jQuery tags were removed.
$old = '<H2 editing="false" revert="Projects:" jQuery1332198888840="12" jQuery1332199361841="12" jQuery1332199407617="12">ProjectsTesting</H2> <UL class=list1 jQuery1332198888840="17" jQuery1332199361841="17" jQuery1332199407617="17"> <LI jQuery1332198888840="16" jQuery1332199361841="16" jQuery1332199407617="16">Praesent vestibulum molestie <LI jQuery1332198888840="19" jQuery1332199361841="19" jQuery1332199407617="19">Aenean nonummy <LI jQuery1332198888840="21" jQuery1332199361841="21" jQuery1332199407617="21">Hendrerit mauris phasellus <LI jQuery1332198888840="23" jQuery1332199361841="23" jQuery1332199407617="23">Porta fusce suscipit varius <LI jQuery1332198888840="25" jQuery1332199361841="25" jQuery1332199407617="25">Cum sociis natoque <LI jQuery1332198888840="27" jQuery1332199361841="27" jQuery1332199407617="27">Penatibus et magnis disI <LI jQuery1332198888840="29" jQuery1332199361841="29" jQuery1332199407617="29">Parturient montes </LI></UL></DIV>';
//This will erase all the jQuery strings.
$new = preg_replace('/jQuery\d+="\d+"/', '', $old);
//This will take out the extra spaces at the end of the tags that was left open.
$new = preg_replace('/\s+>/', '>', $new);
echo $new;
For more information see: http://php.net/manual/en/function.preg-replace.php
If I understand you correctly, this should work:
$myContent = preg_replace('/jQuery\d+="(\d+)"/g', 'jQuery="${1}"', $myContent);
See: http://php.net/manual/en/function.preg-replace.php
I have a blog entry that will sometimes contain a lot of text/images, and I want to cut an excerpt from that blog. To be more specific I want to match everything until after the second image tag
below is some sample text.
I've tried a negative lookaheads like
/[\w\r\n;:',."&\s*<>=-_]+(?!<img)/i
but I can't figure out a way to have the lookahead apply to a '+' modifier. Anyone got any clue, I'd be real grateful.
*override*
I've been stuck in a room lately, and though it's hard to stay creative all the time, sometimes you need that extra kick. Well for some us we have to throw pictures of true creative genius at ourselves to stimulate us.
So sit back and soak in some inspiration I've come across the past year.
<figure>
<a href="">
<img class="aligncenter" src="http://funnypagenet.com/wp-content/uploads/2011/07/Talesandminimalism_12_www.funnypagenet.com_.jpg" alt="" width="574" height="838" />
</a>
<figcaption></figcaption>
</figure>
<h4 style="text-align: center;">
source
</h4>
Couldn't find who did this, but couldn't explain the movie any simpler
<figure>
<img class="aligncenter" src="http://brickhut.files.wordpress.com/2011/05/theempirestrikesback1.jpg" alt="" width="540" height="800" />
<figcaption></figcaption>
</figure>
Obvious a straight forward string cutting is not suitable for your second image:
...
<figure>
<img class="aligncenter" src="http://brickhut.files.wordpress.com/2011/05/theempirestrikesback1.jpg" alt="" width="540" height="800" />
<figcaption></figcaption>
</figure>
Cutting after the image would leave unclosed elements:
...
<figure>
<img class="aligncenter" src="http://brickhut.files.wordpress.com/2011/05/theempirestrikesback1.jpg" alt="" width="540" height="800" />
Which could destroy the rendering of the page inside the browser. And it does not play a role if you use preg_match with a regular expression here or some string functions.
What you need is a DOM parser like DOMDocument that is able to process the HTML:
Given some sample HTML code that is similar to yours in question:
$html = <<<HTML
dolor sit amet, consectetuer adipiscing elit. <img src="http://example.com/img-a.jpg"> Aenean commodo
ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes,
nascetur ridiculus mus.
<figure>
<img src="http://example.com/img-b.jpg">
<figcaption>Figure Caption</figcaption>
</figure>
Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut.
HTML;
You can now use the DOMDocument class to load the HTML chunk inside a <body> tag - because it's your whole html body for the manipulation. As you use non-standard HTML tags (<figure> & <figcaption>) you should disable warnings about those when loading the string with libxml_use_internal_errors:
$doc = new DOMDocument();
libxml_use_internal_errors(1);
$doc->loadHTML(sprintf('<body>%s</body>', $html));
This is the basic setup of the DOM parser, your HTML is now inside the parser. Now comes the interesting part. You want to create the excerpt until the second image of the document. That means, everything after that element should be removed. Sounds as easy as like cutting a string which we know does not work, but this time the DOM parser does all the work for us.
You only need to obtain all nodes (<tag>, Text, <!-- comments -->, ...) and delete them. All nodes after the second <img> tag in (following document order). Such things can be expressed with XPath:
/descendant::img[position()=2]/following::node()
PHP's DOM parser comes with XPath, so let's do it:
$xp = new DOMXPath($doc);
$delete = $xp->query('/descendant::img[position()=2]/following::node()');
foreach ($delete as $node)
{
$node->parentNode->removeChild($node);
}
The only thing left is to obtain (exemplary output) the excerpt that is left over. As we know it's all inside the <body> tag:
foreach ($doc->getElementsByTagName('body')->item(0)->childNodes as $child)
{
echo $doc->saveHTML($child);
}
Which will give you the following:
dolor sit amet, consectetuer adipiscing elit. <img src="http://example.com/img-a.jpg"> Aenean commodo
ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes,
nascetur ridiculus mus.
<figure><img src="http://example.com/img-b.jpg"></figure>
As this example shows, the <figure> tag is properly closed now.
A similar scenario is to create an excerpt after a specific text-length or word-count: Wordwrap / Cut Text in HTML string
Well, it's not regex, but it should work:
$post = str_ireplace('<img', '!!!<img', $post);
list($p1, $p2) = explode('!!!', $post);
$keep = $p1 . $p2;
Puts a split marker before the image tags (!!!), splits on them and keeps the first two chunks, which should be everything up to the second image tag. No regex required.
Edit: Because this is for a excerpt, you might want to run strip_tags() on the result. It's possible that if you don't, you'll have some opened HTML tags that never get closed.
If you really want regex based solution then here it is:
// assuming $str is your full HTML text
if ( preg_match_all('~^(.*?<img\s.*?<img\s[^>]*>)~si', $str, $m) )
print_r ( $m[1] );