WordPress loop by function - wordpress

I'm creating magazine style theme (not e-commerce) and I want to display 3 latest posts from ex. X, Y and Z category, where this 1st post will be with thumb and other 2 only titles. I found some similar solution themes, but when I look into the code, they created 2 loop for each category (2x3=6) and with this 6 loops code looks very messy. So I decided to create function (ex. latest_post_from_category($cat);) to display this post.
Here comes the question is my decision right, if yes do have any advices to make this function more flexible?
Thanks for your time.

a function can become more flexible with params and switches. example follows
function getPosts($type,$return = false,$amount = 4)
{
switch($type)
{
case 'comments':
//Get latest comments here
break;
case 'posts':
case 'posts-desc':
case 'posts-asc':
if($type == 'posts-asc'){ $order = 'ASC';}else{$order = 'DESC';/*default*/}
//Get posts
break;
/*(etc...etc)*/
}
}
$comments = getPosts('comments',true,5); //5 comments
$posts= getPosts('posts-desc',true,6); //5 Latest
Things like that can really make a design come together.
The Thumbs
In regards to this you only really need the post id and wordpress provide the functions so with my example above you can loop and do an if statement
$i = 0;
foreach(getPosts('post-asc',true,3) as $row)
{
$i++;
if($i == 1)
{
//Show thumb for $row
if(!wct_display_thumb("width:200px;height:150px", $row->ID))
{
//Show title
}
}else
{
//Show title for $row!
}
}

Related

How to get total number of rows in a drupal view alter hook?

I've to avoid duplicate search result in a view, so what I am trying to alter the view using pre render hook. and removing the duplicates it's working fine but the problem is in the count of result. it shows the count from the query executed and this include the duplicated item too. also, I enabled the pagination with limit of 5 in a page. then the count seems to be strange it's taking the count of the elements showing in each page
function search_helper_views_pre_render(\Drupal\views\ViewExecutable $view) {
if ($view->id() == "all_news" || $view->id() == "all_publications" || $view->id() == "all_events" || $view->id() == "global_search") {
$unique_nids = $d_nids = $new_results = array();
// Loop through results and filter out duplicate results.
foreach($view->result as $key => $result) {
if(!in_array($result->nid, $unique_nids)) {
$unique_nids[] = $result->nid;
}
else {
unset($view->result[$key]);
}
}
$view->total_rows = count($view->result);
//$view->pager->total_items = count($view->result);
$view->pager->updatePageInfo();
}
}
the expected output of the $view->total_rows must be the total count of result instead of count of elements shown in the page.
You totaly done it in wrong way. as you see ( and it's clear from its name ), it's hook__views_pre_render it runs before the rendering. So its really hard to manipulate the views results and counter, pagination there.
As I see in your query you just remove duplicate Nids , so you can easily do it by Distinct drupal views feature.
Under Advanced, query settings, click on settings.
You will get this popup, now checkmark Distinct
Could do
$difference = count($view->result) - count($new_result);
$view->total_rows = $view->total_rows - $difference;
BTW Distinct setting doesn't always work, see https://www.drupal.org/project/drupal/issues/2993688

Algorithm to Save Items with Parent-Child Relationship to Database

I need help designing the logic of an app that I am working on.
The application should enable users to create mindmaps and save them to a mysql database for later editing.
Each mindmap is made up of inter-related nodes, meaning a node should have a parent node and the id of the mindmap to which it belongs.
I am stuck here. How can I save the nodes to the database and be able to query and rebuild the mindmap tree from the query results.
Root
Child1
Child2
GrandChild1
GreatGrandChild1
GreatGrandChild1
Child3
GrandChild2
I need an algorithm, that can save the nodes and also be able to figure out the relationships/order of items similar to the Tree that I have given. This is very much like how menus are saved and retrieved in Wordpress but I can't find the right logic to do this.
I know there are really great people here. Please help.
This is very easy in a 3 column table.
Column-1: id, Column-2: name, Column-3: parent_id
for example, the data would be like this:
1 ROOT NULL
2 Child1 1
3 Child2 1
... and so on..
I finally found a solution. Here's my full code.
require_once('config.php');//db conn
$connect = mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_select_db(DB_NAME);
$nav_query = MYSQL_QUERY("SELECT * FROM `nodes` ORDER BY `id`");
$tree = ""; // Clear the directory tree
$depth = 1; // Child level depth.
$top_level_on = 1; // What top-level category are we on?
$exclude = ARRAY(); // Define the exclusion array
ARRAY_PUSH($exclude, 0); // Put a starting value in it
WHILE ( $nav_row = MYSQL_FETCH_ARRAY($nav_query) )
{
$goOn = 1; // Resets variable to allow us to continue building out the tree.
FOR($x = 0; $x < COUNT($exclude); $x++ ) // Check to see if the new item has been used
{
IF ( $exclude[$x] == $nav_row['id'] )
{
$goOn = 0;
BREAK; // Stop looking b/c we already found that it's in the exclusion list and we can't continue to process this node
}
}
IF ( $goOn == 1 )
{
$tree .= $nav_row['name'] . "<br>"; // Process the main tree node
ARRAY_PUSH($exclude, $nav_row['id']); // Add to the exclusion list
IF ( $nav_row['id'] < 6 )
{ $top_level_on = $nav_row['id']; }
$tree .= build_child($nav_row['id']); // Start the recursive function of building the child tree
}
}
FUNCTION build_child($oldID) // Recursive function to get all of the children...unlimited depth
{
$tempTree='<ul>';
GLOBAL $exclude, $depth; // Refer to the global array defined at the top of this script
$child_query = MYSQL_QUERY("SELECT * FROM `nodes` WHERE parent_id=" . $oldID);
WHILE ( $child = MYSQL_FETCH_ARRAY($child_query) )
{
IF ( $child['id'] != $child['parent_id'] )
{
FOR ( $c=0;$c<$depth;$c++ ) // Indent over so that there is distinction between levels
{ $tempTree .= " "; }
$tempTree .= "<li>" . $child['name'] . "</li>";
$depth++; // Incriment depth b/c we're building this child's child tree (complicated yet???)
$tempTree .= build_child($child['id']); // Add to the temporary local tree
$depth--; // Decrement depth b/c we're done building the child's child tree.
ARRAY_PUSH($exclude, $child['id']); // Add the item to the exclusion list
}
}
RETURN $tempTree.'</ul>'; // Return the entire child tree
}
ECHO $tree;
?>
This is based on the piece of code found here http://psoug.org/snippet/PHP-Recursive-function-to-generate-a-parentchild-tree_338.html I hope this helps someone as well

get_categories order by meta key issue?

I'm trying to search for a way to order categories by meta value. From what I read, it seems like I can use:
get_categories('child_of=92&hide_empty=false&orderby=meta_value&meta_key=date&order=ASC');
However, this does not work at all, the categories are still not in the order I want. I wonder how I can:
correct this to make it work
print out the sql to see what is really going on inside?
Thank you very much in advance.
First of all, I must mention that I'm using the module custom category fields, and second of all I'm a complete WP newbie
Anyhow, after learning that this cannot be done by default, I looked into the get_categories functions and finally came up with a solution
function category_custom_field_get_terms_orderby( $orderby, $args ){
if($args['orderby'] == 'category_custom_field' && isset($args['category_custom_field']))
return 'cv.field_value';
return $orderby;
}
function category_custom_field_get_terms_fields( $selects, $args ){
if($args['orderby'] == 'category_custom_field' && isset($args['category_custom_field']))
$selects[] = 'cv.*';
return $selects;
}
function category_custom_field_terms_clauses($pieces, $taxonomies, $args){
global $wpdb;
if($args['orderby'] == 'category_custom_field' && isset($args['category_custom_field']))
$pieces['join'] .= " LEFT JOIN $wpdb->prefix" . "ccf_Value cv ON cv.term_id = tt.term_id AND cv.field_name = '".$args['category_custom_field']."'";
return $pieces;
}
add_filter('get_terms_orderby', 'category_custom_field_get_terms_orderby',1,2);
add_filter('get_terms_fields', 'category_custom_field_get_terms_fields',1,2);
add_filter('terms_clauses', 'category_custom_field_terms_clauses',1,3);
(The code above can be put into the theme functions.php file)
then the code to get categories is:
get_categories('child_of=92&hide_empty=false&orderby=category_custom_field&category_custom_field=date&order=DESC');
Any correction is greatly appreciated!
You can also give the get_categories new meta and sort using usort.
$subcategories = get_categories();
foreach ($subcategories as $subcategory) {
$subcategory->your_meta_key = your_meta_value;
}
foreach ($subcategories as $subcategory) {
blah blah blah
}
function my_cmp($a, $b) {
if ($a->ordering == $b->ordering) {
return 0;
}
return ($a->ordering < $b->ordering) ? -1 : 1;
}
usort($subcategories, "my_cmp");

Rss feeds: get certain amount of tweets

Is it possible to give a parameter when getting the RSS feeds to determine how many feeds it should get?
I don't want to load all the RSS feeds, but only the first 20. Is this possible?
Thanks!
You can set the limit. By executing a Loop in limit. So it will parse the xml and your program will read items in loop. Once the loop crossed the limit. Just break the loop.
$i=0;
while ($reader->read()) {
if($i>=10)
break;
else{
switch ($reader->nodeType) {
case (XMLREADER::ELEMENT):
if ($reader->localName == "item") {
$node = $reader->expand();
$dom = new DomDocument();
$n = $dom->importNode($node,true);
$dom->appendChild($n);
$sxe = simplexml_import_dom($n);
$url = (String)$sxe->url;
$title=(String)$sxe->title;
}
}
}
In the above code $i is the limiter. Where we can limit number feed to display in the page.

Drupal module_invoke() and i18n

I am tasked with i18n-ing our current CMS setup in Drupal.
The problem that I am facing is with use of module_invoke() to place blocks within nodes.
I have managed to string translate blocks, and that is working when a block is placed in a region (block content is successfully translated) using the UI.
However, when a block is injected into a node like such:
$block = module_invoke('block', 'block', 'view', 22); print $block['content'];
It is not getting translated, or even worse, not showing at all.
I have also tried this variation using t(). e.g.:
$block = module_invoke('block', 'block', 'view', 22); print t($block['content']);
to no avail.
Generally speaking I've having a bit of trouble with blocks for i18n. Does anyone have a recommended approach for dealing with blocks in drupal with regards to translating them? I would prefer not to create different blocks for each language.
So .. After digging around in the bowels of Drupal - and much hair pulling .. I've come up with an almost decent solution.
Basically, with this function, I can extract a translated version of a block:
function render_i18n_block($block_id, $region = "hidden"){
if ($list = block_list($region)) {
foreach ($list as $key => $block) {
// $key == <i>module</i>_<i>delta</i>
$key_str = "block_".$block_id;
if ($key_str == $key){
return theme('block', $block);
}
}
}
}
Then, in my node, I simple call:
<?php echo render_i18n_block(<block_id>,<region>); ?>
There can be some issues where your blocks might not be displaying in a region (and therefore you can't pass a region into block_list). For this case, I simply created a region called "hidden" which is not rendered anywhere in my template, but can be used to call block_list.
Finally (and this is the part that I still need to find a good solution for), I discovered that block_list() in: includes/blocks/block.inc has a bit of an issue.
It appears that $theme_key is not reliably set unless block_list() is being called from the theme() function (in includes/themes.inc) .. this causes the SQL to return an empty results set. The SQL looks like this:
$result = db_query(db_rewrite_sql("SELECT DISTINCT b.* FROM {blocks} b LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta WHERE b.theme = '%s' AND b.status = 1 AND (r.rid IN (". db_placeholders($rids) .") OR r.rid IS NULL) ORDER BY b.region, b.weight, b.module", 'b', 'bid'), array_merge(array($theme_key), $rids));
As you can see, if theme_key is not set, then it will just return an empty result.
For now I am bypassing this by simply adding:
if (!isset($theme_key)){$theme_key="<my_theme_name>";}
in modules/blocks/block.inc::block_list() around line 429 .. I still need to work out a better way to do this.
10 for anyone with suggestions on how I could ensure that $theme_key is set before calling block_list :)
I had exactly the same problem as you, since I was using
$block = module_invoke('block', 'block_view', 'block_id');
print render($block['content']);
to inject the block into my nodes. However, looking up module_invoke in the Drupal reference, I found a comment titled "to render blocks in Drupal 7 better to use Block API", with this code:
function block_render($module, $block_id) {
$block = block_load($module, $block_id);
$block_content = _block_render_blocks(array($block));
$build = _block_get_renderable_array($block_content);
$block_rendered = drupal_render($build);
return $block_rendered;
}
I just un-functioned it to use directly, like so:
$block = block_load('block', 'block_id');
$block_content = _block_render_blocks(array($block));
$build = _block_get_renderable_array($block_content);
print render($build);
And for me it works like a charm. Be aware however that this method prints the block title as well, so maybe you'll want to set it to 'none' in the original language.
Create a function like this
<?php
function stg_allcontent2($allC, $level
= "1") {
global $language; $lang = $language->language;
foreach ($allC as $acKey => $ac) {
if($ac['link']['options']['langcode']
== $lang){ if ($level == "1")
$toR .= "";
if (is_array($ac['below']))
$class="expanded"; else
$class="leaf";
$toR .= "<li class=\"".$class."\">" . l($ac['link']['link_title'], $ac['link']['link_path']) . "</li>";
if ($level != "1") $toR .= ""; if (is_array($ac['below'])) $toR .= "<ul class=\"menu\">".stg_allcontent2($ac['below'], "2")."</ul>"; if ($level == "1") $toR .= ""; }
}
return $toR; } ?>
call like this
<?php echo '<ul class="menu">'; echo stg_allcontent2(menu_tree_all_data($menu_name
= 'menu-header', $item = NULL)); echo '</ul>'; ?>
This may help you: http://drupal-translation.com/content/translating-block-contents#
UPDATE: the t() function allows you to pass in the language code to use.

Resources