I want to extend Nodes with the title of the parentnode so I can display a hierarchy link.
I have a solution that sometimes works:
function modulename_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL)
{
switch ($op)
{
case 'view':
loadParentTitle($node);
break;
}
}
function loadParentTitle(&$node)
{
$title = $node->title;
$query = "SELECT mlid, p1, p2,p4,p5,p6,p7,p8,p9 FROM menu_links WHERE link_title like '%%%s%%'";
$data = db_fetch_array(db_query($query, $title));
$mlid = $data["mlid"];
$i = 9;
while (($data["p". $i] == 0 || $data["p". $i] == $mlid) && $i >= 0)
{
$i--;
}
if ($i > 0)
{
$query = "SELECT `link_title` as parentTitle from `menu_links` WHERE mlid = " . $data["p" . $i];
$data = db_fetch_array(db_query($query));
$parentTitle = ($data["parentTitle"]);
}
else
{
$parentTitle = $title;
}
$node->content['#parentTitle'] = $parentTitle;
}
This works as long as the title of the item is the same as the Menu Title. However i'm looking for a solution that will work all the time. Any ideas?
You did not specify really what do you mean by 'parent node' but the mlid of the parent of a menu link is stored in menu_links.plid. Now, the link_path is going to be node/nid and you can fetch the title from there.
$mlid = db_result(db_query("SELECT plid FROM {menu_links} WHERE link_path = 'node/%d'", $node->nid));
$link_path = db_result(db_query("SELECT link_path FROM {menu_links} WHERE mlid = %d", $mlid));
$title = db_result(db_query("SELECT title FROM {node} WHERE nid = %d", substr($link_path, 5));
The first two queries can be unified by a JOIN but I strongly recommend against getting the third in there too (you can with CONCAT('node/', nid) = parent.link_path) because that is not going to be indexable. These three queries should be practically instant.
P.S. You won't forget to check_plain($title) before printing, would you? :)
Related
I am having some trouble getting this loop to work properly.
I want to insert Country, State, City, Community from google maps as heiarchy in a custom taxonomy of wordpress. All the variables get set but when it runs through the for loop it only populates and inserts the country or 1st array $loop[0].
I am using $pastID[$d] to save the last term_id to use it as the parent in the next term. If this is just bad let me know.
I have to use Globals as I am connecting with an existing plugin also.
$custom_tax_name = "location";
$loop = array();
$loop[0] = $country = $GLOBALS['custom_array']['country'];
$loop[1] = $state = $GLOBALS['custom_array']['state'];
$loop[2] = $city = $GLOBALS['custom_array']['city'];
$loop[3] = $community = $GLOBALS['custom_array']['community'];
$pastID = array();
$terms = array();
for($i = 0; $i<=3; $i++) {
$d = $i - 1;
if (!empty($loop[$i])){
$term_exist = term_exists( $loop[$i], $custom_tax_name );
if (!$term_exist){
if ($i == 0){
$pastID[$d] = wp_insert_term("$loop[$i]", $custom_tax_name);
} else {
if (empty($pastID[$d]['term_id'])){
$term = get_term_by('name', $loop[$i], $custom_tax_name);
$termParent = $term ? $term->parent : false;
if ($termParent == false){
continue;
}
$pastID[$d] = wp_insert_term("$loop[$i]", $custom_tax_name, array("parent" => $termParent));
} else {
$termParent = $pastID[$d]['term_id'];
$pastID[$d] = wp_insert_term("$loop[$i]", $custom_tax_name, array("parent" => $termParent));
}
}
} else {
$pastID[$d] = $term_exist;
}
$terms[] = $loop[$i];
delete_option('{$custom_tax_name}_children');
} // nothing exist
}
Ok So I was able to figure this out after taking a look and feel a little slow here.
the $pastID needed to have $i variable when setting it and $d when referencing it on the next loop. The code below will create a hierarchy taxonomy up to 4+ deep using my variables for country, state, city, and community. It will check if the variable exist and if it does not it will make sure it has a parent to associate it with or not insert it. Anyways thanks.
for($i = 0; $i<=3; $i++) {
$d = $i - 1;
if (!empty($loop[$i])){
$term_exist = term_exists( $loop[$i], $custom_tax_name );
if (!$term_exist){
if ($i == 0){
$pastID[$i] = wp_insert_term($loop[$i], $custom_tax_name);
} else {
if (empty($pastID[$d]['term_id'])){
$term = get_term_by('name', $loop[$i], $custom_tax_name);
$termParent = $term ? $term->parent : false;
if ($termParent == false){
continue;
}
$pastID[$i] = wp_insert_term($loop[$i], $custom_tax_name, array("parent" => $termParent));
} else {
$termParent = $pastID[$d]['term_id'];
$pastID[$i] = wp_insert_term("$loop[$i]", $custom_tax_name, array("parent" => $termParent));
}
}
} else {
$pastID[$d] = $term_exist;
}
$terms[] = $loop[$i];
delete_option('{$custom_tax_name}_children');
} // nothing exist
}
From my application, I send a list of users that I want to search the group they are subscribed:
$selectedUsers = ["John", "Carlos", "Anna", "Julia"]
I have in my database many different groups with many different users in
each of them:
$football = ["**John**" ,"**Carlos**" ,"Daniel" ,"Rob" ,"Frank" ,"Bob"]
$cooking = ["**John**" , "**Anna**" , "**Julia**" , "Claudia" , "Rob" , "Adriana"]
$startups = ["**John**", "**Carlos**", "**Anna**", "**Julia**", "Rob", "Adriana"]
The output I want to have is the sorted list of groups with the amount of the selectedUsers in it:
$returnArray[0] = $startups //4 users inside group
$returnArray[1] = $cooking //3 users inside group
$returnArray[2] = $football //2 users inside group
Here is the code I have so far, but the loop I'm using is based on the group_id I've stored and I want to change that:
<?php
//fetch groups with users
$returnValue = array();
$groupUsersNumber = 0;
$selectedUsers = htmlentities($_REQUEST["selectedUsers"]);
$lastGroupID = htmlentities($_REQUEST["lastGroupID"]); //remove
if($lastGroupID == ""){
$lastGroupID = getLastGroupID();
$lastGroupID = $lastGroupID + 1;
}
if($selectedUsers == ""){
//return all groups ordered by ID desc
$group = getGroupWithID($lastGroupID);
} else{
$usersArray = explode(', ', $selectedUsers);
$foundGroup = false;
while($foundGroup == false){
$group = getGroupWithID($lastGroupID);
$fetchedGroupUsers = explode(', ', $group["users"]);
for($i = 0; $i < count($usersArray); $i++){
if(in_array($usersArray[$i], $fetchedGroupUsers)){
$foundGroup = true;
break;
} else{
$lastGroupID = $group["group_id"];
}
}
}
}
for($i = 0; $i < count($usersArray); $i++){
if(in_array($usersArray[$i], $fetchedGroupUsers)){
$groupUsersNumber = $groupUsersNumber + 1;
}
}
if(empty($group))
{
$returnValue["status"]="403";
$returnValue["message"]="No more groups with that users.";
echo json_encode($returnValue);
return;
} else{
$returnValue=$group;
$returnValue["groupUsersNumber"]=$groupUsersNumber;
}
echo json_encode($returnValue);
?>
Is there any other way to have a better/ more efficient way to search into my database? Appreciated!
It seems that your database is not normalized. A normalized database may be the more efficient way. Do not store users in a describing varchar. Instead establish a many to many relation.
Beside that the FilterIterator class of PHP is something for you. It is reusable and a bit more efficient at iterating over arrays.
Here 's a short example.
class NameFilterIterator extends FilterIterator {
protected $filter = null;
public function __construct(Iterator $iterator, $filter) {
parent::__construct($iterator);
$this->filter = $filter;
}
public function accept() {
$current = $this->getInnerIterator()->current();
if (strpos($current, $this->filter) !== false) {
return true;
}
return false;
}
}
// Usage
$aUsers = [ 'John', 'Carlos', 'Anna', 'Julia' ];
$oFootball = new ArrayIterator(["**John**" ,"**Carlos**" ,"Daniel" ,"Rob" ,"Frank" ,"Bob"]);
foreach ($aUsers as $sUser) {
$oFilter = new NameFilterIterator($oFootball, $sUser);
foreach ($oFilter as $sName) {
var_dump($sName); // outputs: John, Carlos
}
}
The internal memory usage of the FilterIterator object is way more efficient.
You appear to be mixing up php and mysql, and it would be better to redesign your database.
However as a basic idea you can do roughly what you want in MySQL. It is not nice, and not efficient but something like this:-
SELECT a.group_description ,
GROUP_CONCAT(b.wanted_name)
FROM some_table a
LEFT OUTER JOIN
(
SELECT "John" AS wanted_name UNION SELECT "Carlos" UNION SELECT "Anna" UNION SELECT "Julia"
) b
ON FIND_IN_SET(b.wanted_name, a.group_users)
GROUP BY a. group_description
Is there anything to get more performance? Because it tooks about 8 secs. car_models database has over 100.000 records, cars database has over 20.000 records and finaly car_parts has over 20.000 records. I could do for that a database something like keywords. But the problem is the databases are dynamic. I mean the records adding everyday by editors. And I can't touch the part of the software because it is not open source...
$news = dbquery("SELECT * FROM " . DB_NEWS . " ORDER BY news_id DESC LIMIT 0,1");
while ($news_data = dbarray($news))
{
echo $news_data['news_subject'];
$news_first_part = str_replace("\\", "", $news_data['news_news']);
$news_first_part = explode('.', $news_first_part); //first phrase
$news_first_part = $news_first_part[0];
$news_second_part = str_replace("\\", "", $news_data['news_extended']);
$find = array();
$keywords = dbquery("SELECT name FROM cars GROUP BY name");
while ($keywords_data = dbarray($keywords))
{
$my_keyword = $keywords_data['name'];
$news_first_part = str_replace($my_keyword, "<a href='keyword.php?keyword=$my_keyword' title='$my_keyword'>$my_keyword</a>", $news_first_part);
$news_second_part = str_replace($my_keyword, "<a href='keyword.php?keyword=$my_keyword' title='$my_keyword'>$my_keyword</a>", $news_second_part);
if ($news_first_part OR $news_second_part AND !in_array($my_keyword, $find,true))
{
array_push($find, $my_keyword);
}
}
$my_keyword="";
$keywords = dbquery("SELECT name FROM car_models GROUP BY name");
while ($keywords_data = dbarray($keywords))
{
$my_keyword = $keywords_data['name'];
if (strlen($my_keyword) > 10 && !in_array($my_keyword, $find, true))
{
$news_first_part = str_replace($my_keyword, "<a href='keyword.php?keyword=$my_keyword' title='$my_keyword'>$my_keyword</a>", $news_first_part);
$news_second_part = str_replace($my_keyword, "<a href='keyword.php?keyword=$my_keyword' title='$my_keyword'>$my_keyword</a>", $news_second_part);
}
}
$keywords = dbquery("SELECT name FROM car_parts GROUP BY name");
while ($keywords_data = dbarray($keywords))
{
$my_keyword = $keywords_data['name'];
if (strlen($my_keyword) > 10)
{
$news_first_part = str_replace($my_keyword, "<a href='keyword.php?keyword=$my_keyword' title='$my_keyword'>$my_keyword</a>", $news_first_part);
$news_second_part = str_replace($my_keyword, "<a href='keyword.php?keyword=$my_keyword' title='$my_keyword'>$my_keyword</a>", $news_second_part);
}
}
$my_keyword="";
echo $news_first_part . '.'; //note I added the final ponctuation
$news_first_part .= ".";
$news_second_part = str_replace($news_first_part, "", $news_second_part);
echo nl2br($news_second_part);
}
You could build some kind of array tree-structure, to limit the size of the sub-arrays. The array would then become:
$arr['a']['apple'];
$arr['a']['anna'];
$arr['a']['awesome'];
$arr['b']['bread'];
$arr['b']['beer'];
$arr['c']['cucumber'];
Instead of
$arr['apple'];
$arr['anna'];
$arr['awesome'];
$arr['bread'];
$arr['beer'];
$arr['cucumber'];
As you can see, an in_array would become lots faster.
If we would like to check "php", there is no array for the first-letter "p": nothing has to be walked through again
If we would like to check "ananas", we would have to lookup 3 items, instead of 6!
Note: the "outer" array could consist of the 1st letter (or 2, 3, 4, etc.) depending on the size of your set.
In PHP code you would get something like
$word = "ananas";
$arr = array();
if (!isset($arr[$word{0}]) || !in_array($word, $arr[$word{0})) {
// New word
if (!isset($arr[$word{0}])) {
$arr[$word{0}] = array($word);
} else {
$arr[$word{0}][] = $word;
}
}
Try it this way, it is much faster.
if ($news_first_part OR $news_second_part AND !isset($find[$my_keyword]))
{
$find[$my_keyword] = 1;
}
Update the rest of the code correspondingly. Actually, you do not need to use a !isset($find[$my_keyword]) check here.
How would I create a nested list, I currently have this
public function getNav($cat,$subcat){
//gets all sub categories for a specific category
if(!$this->checkValue($cat)) return false; //checks data
$query = false;
if($cat=='NULL'){
$sql = "SELECT itemID, title, parent, url, description, image
FROM p_cat
WHERE deleted = 0
AND parent is NULL
ORDER BY position;";
$query = $this->db->query($sql) or die($this->db->error);
}else{
//die($cat);
$sql = "SET #parent = (SELECT c.itemID FROM p_cat c WHERE url = '".$this->sql($cat)."' AND deleted = 0);
SELECT c1.itemID, c1.title, c1.parent, c1.url, c1.description, c1.image, (SELECT c2.url FROM p_cat c2 WHERE c2.itemID = c1.parent LIMIT 1) as parentUrl
FROM p_cat c1
WHERE c1.deleted = 0
AND c1.parent = #parent
ORDER BY c1.position;";
$query = $this->db->multi_query($sql) or die($this->db->error);
$this->db->store_result(); $this->db->next_result();
$query = $this->db->store_result();
}
return $query;
}
public function getNav($cat=false, $subcat=false){
//gets a list of all categories form this level, if $cat is false it returns top level nav
if($cat==false || strtolower($cat)=='all-products') $cat='NULL';
$ds = $this->data->getNav($cat, $subcat);
$nav = $ds ? $ds : false;
$html = '';
//create html
if($nav){
$html = '<ul>';
//var_dump($nav->fetch_assoc());
while($row = $nav->fetch_assoc()){
$url = isset($row['parentUrl']) ? $row['parentUrl'].'/'.$row['url'] : $row['url'];
$current = $subcat==$row['url'] ? ' class="current"' : '';
$html .= '<li'.$current.'>'.$row['title'].'</li>';
}
$html .='</ul>';
}
return $html;
}
The sql returns parents and children, for each parent I need the child to nest in a list.
It's been a while since I've done any PHP but wondering if this will work. Inside your while loop, could you just recurse and add the output of getNav($cat = $row['url']) again in a new <li>, kind of like:
while($row = $nav->fetch_assoc()){
$url = isset($row['parentUrl']) ? $row['parentUrl'].'/'.$row['url'] : $row['url'];
$current = $subcat==$row['url'] ? ' class="current"' : '';
$html .= '<li'.$current.'>'.$row['title'].'';
/* Add subNav HTML */
$html .= $this->getNav($row['url']);
$html .= '</li>';
}
It seems that "getNav" refers to both the function to get the SQL as well as the function that renders the nav HTML - maybe change the HTML getNav function name to getNavHtml just for clarity.
Also seems like the $subcat argument may be able to be removed from the SQL getNav function since it is never used.
function build_list($id=0,$collapsed="") //return an array with the categories ordered by position
{
$RootPos = "";
$this->c_list = array();
if($id != 0){
$this_category = $this->fetch($id);
$positions = explode(">",$this_category['position']);
$RootPos = $positions[0];
}
// lets fetch the root categories
$sql = "SELECT *
FROM ".$this->table_name."
WHERE position RLIKE '^([0-9]+>){1,1}$' AND c_group = '".$this->Group."'
ORDER BY c_name";
$res = mysql_query($sql) or die(trigger_error("<br><storng><u>MySQL Error:</u></strong><br>".mysql_error()."<br><br><storng><u>Query Used:</u></strong><br>".$sql."<br><br><storng><u>Info:</u></strong><br>",E_USER_ERROR));
while($root = mysql_fetch_array($res)){
$root["prefix"] = $this->get_prefix($root['position']);
$this->c_list[$root['id']] = $root;
if($RootPos == $root['id'] AND $id != 0 AND $collapsed != ""){
$this->list_by_id($id);
continue;
}else{
// lets check if there is sub-categories
if($collapsed == "" AND $id==0){
$has_children = $this->has_children($root['position']);
if($has_children == TRUE) $this->get_children($root['position'],0);
}}}
return $this->c_list;
}
// He is the Author of the code...
Categories Class
Author: Shadi Ali
Now I want to just return the Categories and Sub Categories from the above code.
function browse() {
$categories = new categories;
$categories_list = $categories->build_list();
foreach($categories_list as $c)
{
return $c->$id;
}
}
The above code is not working.... can anyone help me out.
Here are two problems with the browse() function:
The return statement is inside the foreach loop. The statement will return one value for one of the items in the $categories-list (at most), and not continue to loop over the rest of the $categories-list.
The $id variable is never declared or initialised in return $c->$id, perhaps you meant to use $c['id'] or $c->id