Jump to content

Function problem with find and custom selectors on many articles


nikola
 Share

Recommended Posts

I had this structure in template before, but without the functions, and I repetead it manually and it worked fine and fast.

Since I've made 3 function to do it automatically, page render slowed down dramatically (for now I have around 400 articles).

I'm calling these 4 function 5 times on home page (for 5 different main categories).

"kategorije" means "categories"

// Article Header

function homeHeader($category) {
	
	$category = wire('pages')->get("/kategorije/$category/");
	foreach($category->children as $subcategory) {
    	$subcategories[] = $subcategory->id;		
    }
    $array = implode("|",$subcategories);
	
	$articles = wire('pages')->find("subcategory=$array, template=article, sort=-date");
	
	echo "<a href='{$category->url}' class='all-categories'>Sve podkategorije</a>";
                        
	echo "<form class='category-select' method='get' action='#'>";
	echo	"<select name='category' class='selectyze' >";
	echo	"<option>Odaberi podkategoriju</option>";
	echo "<optgroup label='Podkategorije'>";
							
	foreach($category->children as $option) {
		echo "<option value='{$option->url}'>{$option->title}</option>";
	}
    
	echo "</optgroup>";
	echo "</select>";
	echo "</form>";
                        
    echo "<h2><a href='{$category->url}'>{$category->title}</a> <span>(" . count($articles) . ")</span></h2>";
                
	echo "<div class='clear'></div>";

}

// Home Main Article

function homeMainArticle($category, $start) {

	$category = wire('pages')->get("/kategorije/$category/");
	foreach($category->children as $subcategory) {
    	$subcategories[] = $subcategory->name;		
    }
    $array = implode("|",$subcategories);

	$articles = wire('pages')->find("subcategory=$array, template=article, start=$start, limit=1, sort=-date");
	
	foreach($articles as $article) {
	
		if(count($article->images) > 0) {
			$image = $article->images->first();
			echo "<img class='align-left' src='" . $image->getThumb('bigthumb') . "' alt='{$image->description}' width='198' height='136' />";
		} else { 
			$image = "<img class='align-left' src='{$config->urls->templates}img/no-image-198-136.png' width='198' height='136' />";
			echo $image;
		}
		
		echo "<h2><a href='{$article->url}'>{$article->title}</a></h2>";

		$body = strip_tags(preg_replace("/(<h[1-6]>.*?<\/h[1-6]>|\[.*\])/m","",$article->body));
	
		if (strlen($body) > 340) {
			$excerpt = excerpt($body, 0, 340);
			echo "<p>" . $excerpt . '<a href="' . $article->url . '"> više</a></p>';
		} else {
			echo "<p>" . $body . "</p>";
		}

	}

}

// Home Article

function homeArticle($category) {

	$category = wire('pages')->get("/kategorije/$category/");
	foreach($category->children as $subcategory) {
    	$subcategories[] = $subcategory->name;		
    }
    $array = implode("|",$subcategories);
	
	$articles = wire('pages')->find("subcategory=$array, template=article, start=2, limit=4, sort=-date");
	
	foreach($articles as $article) {
	
		echo "<li>";
	
		if(count($article->images) > 0) {
			$image = $article->images->first();
			echo "<img class='img-left' src='" . $image->getThumb('thumb') . "' alt='{$image->description}' width='96' height='64' />";
		} else { 
			$image = "<img class='img-left' src='{$config->urls->templates}img/no-image-96-64.png' width='96' height='64' />";
			echo $image;
		}
		
		echo "<a class='article-title' href='{$article->url}'>{$article->title}</a>";
		
		$body = strip_tags(preg_replace("/(<h[1-6]>.*?<\/h[1-6]>|\[.*\])/m","",$article->body));
		
		if (strlen($body) > 100) {
			$excerpt = excerpt($body, 0, 100);
			echo "<p>" . $excerpt . '<a href="' . $article->url . '"> više</a></p>';
		} else {
			echo "<p>" . $body . "</p>";
		}
	
	echo"</li>";
	
	}

}

What could be wrong?

Link to comment
Share on other sites

I'm not quite sure why this would be any slower when using functions, but here's a couple of things that you could make a bit more effective. Some of it is mostly cosmetic though.

This bit of code:


$category = wire('pages')->get("/kategorije/$category/");
foreach($category->children as $subcategory) {
    $subcategories[] = $subcategory->id;
}
$array = implode("|",$subcategories);

$articles = wire('pages')->find("subcategory=$array, template=article, sort=-date");

Could be written like this (letting the core do what you done yourself):

$array = wire('pages')->find("parent=/kategorije/$category/");
$articles = wire('pages')->find("subcategory=$array, template=article, sort=-date");

The other two functions have the same bit of code, but with $subcategory->name. I would have thought that doesn't even work.. does it? I think you meant the same thing in all those cases anyway.

Then, if you're calling the same functions for the same categories and they all do the same subcategory-thing commented above, it would be better to construct the subcategories just once and use the same array three times. Just give the subcategory array as an additional parameter to the functions you're calling.

Maybe there's something there I didn't see right away, but I hope these help even a little bit :). The effect isn't necessarily huge as ProcessWire does a good job caching previously fetched Page objects, but I guess it's worth a try anyway.

  • Like 1
Link to comment
Share on other sites

Thanks nik,

I ended up with the code in the template itself in one big foreach that outputs the same code above and page executes in one second with all the extra code in header and footer.

It looks like to me that it chokes somewhere when used through function...

Link to comment
Share on other sites

In addition to what Nik mentioned, I would see if you can narrow down where the bottleneck is. Add the following to the beginning of each function:

$timer = Debug::timer();

And add the following to the end of each function:

echo "<p>" . __FUNCTION__ . " with page $category->path executed in " . Debug::timer($timer) . " seconds.</p>";

That might help to narrow it down. 


But if these function calls really are generating navigation with 400+ items, I probably wouldn't expect it to be lightning fast. It would be a good candidate for using MarkupCache. To use MarkupCache, replace all your "echo string" lines in the function with "$out .= string", so that you are populating a variable with the output rather than echoing it. Ideally your functions return the output so that the caller can do the echo, but you could also just put your echo at the bottom of the function. Once you've done that, you can use MarkupCache by putting this at the top of your function:

$seconds = 86400; // 1 day, or 3600=1 hour
$cache = wire('modules')->get('MarkupCache'); 
$out = $cache->get("homeHeader($category)", $seconds); 
if($out) return $out; // or echo $out;

// ...the rest of your function code...

$cache->save($out); 
return $out; // or echo $out; 
  • Like 2
Link to comment
Share on other sites

I've sorted it out. The problem was with the array wrongly set up. It pulled page references that weren't needed at all. I wrapped it all up in a single function and automated categories and subcategories pulling with custom selectors for articles and it works fast and smooth :)

Thanks for your help guys!

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...