WordPress Custom Query for Taxonomy - mysql

I have to edit somebody's code and I am not familiar with querying posts using the method they are. I have tried editing the query to various alternatives, however I am having no luck. I want to change the following query to select data from a custom taxonomy called 'job_cat' where the value equals a POST value. The code is below:
$querystr = "
SELECT DISTINCT wposts.*
FROM $wpdb->posts wposts
LEFT JOIN $wpdb->postmeta wpostmeta ON wposts.ID = wpostmeta.post_id
LEFT JOIN $wpdb->postmeta wpostmeta2 ON wposts.ID = wpostmeta2.post_id
LEFT JOIN $wpdb->term_relationships ON (wposts.ID = $wpdb->term_relationships.object_id)
LEFT JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)
WHERE wp_term_taxonomy.term_id = 94";
// If a job type is set and not equal to nothing or any jobs
if(isset($_POST['search-location']) && $_POST['search-location'] !== "" && $_POST['search-location'] !== "All") {
$querystr .= " AND (wpostmeta2.meta_key = 'region' AND wpostmeta2.meta_value = '".$_POST['search-location']."')";
}
$querystr .= " ORDER BY post_date DESC LIMIT 50";
//Execute
//echo $querystr;
$pageposts = $wpdb->get_results($wpdb->prepare($querystr, OBJECT));
Any help would be great!!

This code is extremely dangerous to use in a production WordPress site. You need to remove it and any other template file larded up with SQL queries like this.
Instead, use WP_Query which automatically sanitizes your SQL requests. It has a huge number of parameters you can set to query anything from WordPress. Here is an example using WP_Query to get posts by a given taxonomy, with tax_query.
<?php
// 1- Setup an argument to give to WP_Query
$taxonomy_args = array(
// 2- use the tax_query to examine a taxonomy
'tax_query' => array(
array(
'taxonomy' => 'job_cat',
'terms' => 'XYZ',
'field' => 'slug',
'include_children' => true,
'operator' => 'IN'
)
),
// 3- Make sure to define how many posts and what post-type they should be
'posts_per_page' => 50,
'post_type' => 'search-location',
);
$s = new WP_Query( $some_args );
if ( $s->have_posts() ) : $s->the_post();
// 4- Here you will manipulate the data you get back
endif;
?>

Related

How to transform raw SQL into Yii2 like find query

I can't convert raw SQL query in to Yii2 like method. I'd like to implement grid view from my RAW sql with filtering and sorting. I'm using ActiveDataProvider with method in the ModelSearch as Yii default way.
I did try to use Model::findBySql but it is not letting me filter or sort my results in the grid view. I don't want to useSQLDataProvider because I have relations in my queries.
I see that changing Model::FindBySql($sql) to Model::find is letting me sort and filter but the results are not as expected. I have to transform this SQL to use Model::Find() method
My sql I struggle to change is
$sql = 'SELECT A.*, (6371 * acos(cos(radians("'.$mapSearch->gps_lat.'")) * cos(radians(gps_lat))*cos(radians(gps_long)-radians("'.$mapSearch->gps_long.'"))+sin(radians("'.$mapSearch->gps_lat.'"))*sin(radians(gps_lat)))) AS distance FROM address A JOIN contest_has_address CA On A.id = CA.address_id JOIN contest C On C.id = CA.contest_id JOIN contest_has_date CD On C.id = CD.contest_id JOIN date D On D.id = CD.date_id WHERE main = 1 AND C.status = 1 AND D.start_time > "'.$today.'" HAVING distance < "'.$mapSearch->distance.'" ORDER BY distance ASC';
my Controller:
if($mapSearch->save(false)) {
$lat = $mapSearch->gps_lat;
$long = $mapSearch->gps_long;
$sql = 'SELECT A.*, (6371 * acos(cos(radians("'.$mapSearch->gps_lat.'")) * cos(radians(gps_lat))*cos(radians(gps_long)- radians("'.$mapSearch->gps_long.'"))+sin(radians("'.$mapSearch->gps_lat.'") )*sin(radians(gps_lat)))) AS distance FROM address A JOIN contest_has_address CA On A.id = CA.address_id JOIN contest C On C.id = CA.contest_id JOIN contest_has_date CD On C.id = CD.contest_id JOIN date D On D.id = CD.date_id WHERE main = 1 AND C.status = 1 AND D.start_time > "'.$today.'" HAVING distance < "'.$mapSearch->distance.'" ORDER BY distance ASC';
$models = Address::findBySql($sql)->all();
$count = Yii::$app->db->createCommand($sql)->queryScalar();
$dataProvider = $searchModel->searchMapAddress(Yii::$app->request->queryParams, $sql);
return $this->render('map', [
'sql'=>$sql,
'searchModel'=>$searchModel,
'models'=>$models,
'dataProvider'=>$dataProvider,
'mapSearch'=>$mapSearch,
'lat'=>$mapSearch->gps_lat,
'long'=>$mapSearch->gps_long,
]);
My Model
$query = Address::findBySql($sql);
$query->joinWith(['contest']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
and view:
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'layout'=> '{items}',
Assuming that your raw SQL query is working correctly you can use ActiveRecord or Query Builder to create your query.
For using MYSQL functions inside the query you must use \yii\db\Expresion, and while building the query you should use ->createCommand()->rawSQL at the end of the query replacing with ->one() or ->all(), and echo the query to see what the RAW SQL query is built and compare it with the original query.
You can use the following query:
$query=Address::find()->alias('A')
->select([new Expression('A.*, (6371 * acos(cos(radians("' . $mapSearch->gps_lat . '")) * cos(radians(gps_lat))*cos(radians(gps_long) -radians("' . $mapSearch->gps_long . '")) + sin(radians("' . $mapSearch->gps_lat . '"))*sin(radians(gps_lat)))) AS distance')])
->join('left join', '{{content_has_address}} CA', 'A.id = CA.address_id')
->join('left join', '{{contest}} C', 'C.id = CA.contest_id')
->join('left join', '{{contest_has_date}} CD', 'C.id = CD.contest_id')
->join('left join', '{{date}} D', 'D.id = CD.date_id')
->where(
['AND',
['=', 'main', 1],
['=', 'C.status', 1],
['>', 'D.start_time', $today]
]
)
->having(['<', 'distance', $mapSearch->distance])
->orderBy('distance asc');
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);

yii1 CGridview with custom SQL

i need to use yii1 CGridView with the custom SQL.
i have followed this article
inside model I've created
public function searchUserStats()
{
$count = Yii::app()->db->createCommand()
->select('count(DISTINCT user_id)')
->from('casino_sg_sessions')
->queryScalar();
$sql = '
SELECT
SUM(bet) bet_sum,
SUM(win) win_sum,
SUM(bet_count) bet_count,
user_id,
userName,
modified
FROM
(SELECT
(SELECT IFNULL(SUM(tr1.amount), 0) FROM casino_sg_transactions tr1 WHERE t.id = tr1.session_id AND tr1.action = \'bet\' ) AS bet,
(SELECT IFNULL(SUM(tr2.amount), 0) FROM casino_sg_transactions tr2 WHERE t.id = tr2.session_id AND tr2.action = \'win\' ) AS win,
(SELECT count(0) FROM casino_sg_transactions tr3 WHERE t.id = tr3.session_id) AS bet_count,
t.user_id,
u.userName,
t.modified
FROM `casino_sg_sessions` t
INNER JOIN user u ON u.id = t.user_id
ORDER BY modified DESC
) user_stats
GROUP BY user_id
ORDER BY modified DESC
';
$command = Yii::app()->db->createCommand($sql);
$dataProvider = new CSqlDataProvider($command, array(
'totalItemCount'=>$count,
'pagination'=>array(
'pageSize'=>15,
),
));
return $dataProvider;
}
in the controller:
$model = new CasinoSgSessions('searchUserStats');
$this->render('index', array(
'model' => $model,
));
inside the view i call it this way:
$this->widget('application.widgets.grid.CGridView', array(
'dataProvider' => $model->searchUserStats(),
'filter' => $model,
'columns' => array(
[
'header' => 'User ID',
'name' => 'user_id',
'value' => '$data->user_id',
'htmlOptions' => array('width'=>'150px'),
],
.....
.....
i receive paginated grid without data.
spent huge amount of time and now gave up, what i did wrong ?
sql query itself works good.
PS: i cant use mysql views and create model for the view.
PPS: query will be a bit more complex, so the only way i see is using CGridView through the sql query.
in the template instead of
$data->user_id
i had to use
$data['user_id']
absolutely not expected behavior. Seems to me they didn't hear about SOLID

Zend Framework 2 SQL Join Issue

I am trying to use two left outer joins with Zend Framework 2's SQL classes but for some reason it is not returning one result but the other one is working fine. I've ran the actual SQL in MySQL Workbench and it returns just like I want but it is not doing it with Zend Framework. Here is my code:
Pure SQL:
SELECT groups.group_name, members.username, groups.id FROM groups
LEFT OUTER JOIN group_admins ON groups.id = group_admins.group_id
LEFT OUTER JOIN members ON group_admins.user_id = members.id
WHERE group_admins.user_id = " . parent::getUserId()['id']
This returns the result I wish, (which can be seen here: http://imgur.com/8ydmn4f)
Now, here is the Zend Framework 2 code I have in place:
$select_admins = new Select();
$select_admins->from(array(
'g' => 'groups',
))
->join(array(
'ga' => 'group_admins'
), 'g.id = ga.group_id')
->join(array(
'm' => 'members'
), 'ga.user_id = m.id', array('username'))
->where(array('ga.user_id' => parent::getUserId()['id']));
$query_group_admin = parent::$sql->getAdapter()->query(parent::$sql->buildSqlString($select_admins), Adapter::QUERY_MODE_EXECUTE);
$group_admins = array();
foreach ($query_group_admin as $group_admin) {
$group_admins[] = $group_admin;
}
// get the group members
$select = new Select();
$select->from(array(
'g' => 'group_members'
))
->join(array(
'm' => 'members'
), 'g.member_id = m.id')
->join(array(
'grp' => 'groups'
), 'g.group_id = grp.id')
->where(array(
'g.group_id' => $group_id
));
$query = parent::$sql->getAdapter()->query(parent::$sql->buildSqlString($select), Adapter::QUERY_MODE_EXECUTE);
$member_username = array();
foreach ($query as $member) {
$member_username[] = $member['username'];
}
// get the rest of the group info
$fetch = $this->gateway->select(array(
'id' => $group_id
));
$row = $fetch->current();
if (!$row) {
return false;
}
return array(
'admins' => implode(", ", $group_admins),
'members' => implode(", ", $member_username),
'info' => $row
);
Controller:
public function grouphomeAction()
{
$id = $this->params()->fromRoute('id', 0);
if (0 === $id) {
return $this->redirect()->toRoute('members/groups', array('action' => 'index'));
}
if (!$this->getGroupsService()->getGroupInformation($id)) {
return $this->redirect()->toRoute('members/groups', array('action' => 'index'));
}
return new ViewModel(array('group_info' => $this->getGroupsService()->getGroupInformation($id)));
}
However, this only shows the group name, group creator and group members but leave the group admins field empty.
Here is the print_r result of the array returned:
Array ( [admins] => [members] => jimmysole, fooboy [info] => ArrayObject Object ( [storage:ArrayObject:private] => Array ( [id] => 2 [group_name] => Tim's Group [group_creator] => timlinden [group_created_date] => 2017-01-16 17:39:56 ) ) )
If it helps, here is a screenshot as well of the page - http://imgur.com/xUQMaUu
Any help would be appreciated!
Thanks.
Basically your joins are INNER JOINS...I know....you must hate Zend right now :p . By default they are INNER JOINS so i assume that is what is wrong. SO try to specify the type of join and you should be fine. You can find more examples here: examples
$select12->from('foo')->join('zac', 'm = n', array('bar', 'baz'), Select::JOIN_OUTER);

How to search posts of specific custom post type by a custom field value and then "filter" the results by a custom field checkbox value?

I have a custom post type (songs) and several custom fields associated with it. One of the custom fields is a checkbox (sample_playlist), the rest are text strings.
I have added a select element and I am using the checkbox value to filter the results when on edit.php?post_type=songs
add_filter( 'parse_query', array( &$this, 'wpse45436_posts_filter' ) );
function wpse45436_posts_filter( $query ){
// current page and post type checks omitted
$query->query_vars['meta_key'] = 'sample_playlist';
$query->query_vars['meta_value'] = 'on'; //these are the queries that get executed when filtering the posts that have the custom field checkbox checked
}
This works fine when I only attempt to filter the results based on the checkbox value.
Searching by other custom field values is also possible on that same page via
add_filter( 'posts_join', array( &$this, 'songs_search_join' ) );
add_filter( 'posts_where', array( &$this, 'songs_search_where' ) );
function songs_search_join ($join){
// current page, post type and $_GLOBAL['s'] checks omitted
$join .='LEFT JOIN '.$wpdb->postmeta. ' ON '. $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
return $join;
}
function songs_search_where( $where ){
// current page, post type and $_GLOBAL['s'] checks omitted
$where = preg_replace(
"/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
"(".$wpdb->posts.".post_title LIKE $1) OR (".$wpdb->postmeta.".meta_value LIKE $1)", $where
);
return $where;
}
The search works fine when I only try to search terms by custom field values.
HOWEVER, when I try to use both of these sequentially (ie search then filter, or vice versa), I run into a problem with the search join using wp_postmeta as well as the filter by "custom field checkbox value" using it as well. Is there a way around this, that would allow me to utilize both of these sequentially?
the error I recieve: WordPress database error Not unique table/alias: 'wp_postmeta'
the resulting sql query output:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)LEFT JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id WHERE 1=1 AND (((wp_posts.post_title LIKE '%searchterm%') OR (wp_postmeta.meta_value LIKE '%searchterm%') OR (wp_posts.post_content LIKE '%searchterm%'))) AND wp_posts.post_type = 'songs' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'future' OR wp_posts.post_status = 'draft' OR wp_posts.post_status = 'pending' OR wp_posts.post_status = 'private') AND ( (wp_postmeta.meta_key = 'sample_playlist' AND CAST(wp_postmeta.meta_value AS CHAR) = 'on') ) ORDER BY wp_posts.post_date DESC LIMIT 0, 20
I needed to use an alias for $wpdb->postmeta in my search:
add_filter( 'posts_join', array( &$this, 'songs_search_join' ) );
add_filter( 'posts_where', array( &$this, 'songs_search_where' ) );
function songs_search_join ($join){
// current page, post type and $_GLOBAL['s'] checks omitted
$join .='LEFT JOIN '.$wpdb->postmeta. ' p ON '. $wpdb->posts . '.ID = p.post_id ';
return $join;
}
function songs_search_where( $where ){
// current page, post type and $_GLOBAL['s'] checks omitted
$where = preg_replace(
"/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
"(".$wpdb->posts.".post_title LIKE $1) OR (p.meta_value LIKE $1)", $where
);
return $where;
}

Doctrine2 LEFT JOIN with 2 conditions

I'm trying to find a 'Product' by ID, and to left join all it's 'Photo' on two conditions: the locale AND the active state.
Here's my QueryBuilder :
$queryBuilder = $this->createQueryBuilder('p')
->select('p, photos, photoTranslation')
->leftJoin('p.photos', 'photos')
->leftJoin('photos.translations', 'photoTranslation')
->where('p.id = :id')
->andWhere('(photoTranslation.locale = :locale OR photoTranslation.locale IS NULL)')
->andWhere('(photoTranslation.active = :active OR photoTranslation.active IS NULL)')
->setParameters(array(
'id' => $id
'locale' => $this->getLocale(),
'active' => true
));
It works fine when there are no Photos or when there are ACTIVE photos, but not when there's an inactive Photo because it doesn't match one of the two conditions.
If I use only one condition, for instance only the locale part, it works fine :
$queryBuilder = $this->createQueryBuilder('p')
->select('p, photos, photoTranslation')
->leftJoin('p.photos', 'photos')
->leftJoin('photos.translations', 'photoTranslation')
->where('p.id = :id')
->andWhere('(photoTranslation.locale = :locale OR photoTranslation.locale IS NULL)')
->setParameters(array(
'id' => $id
'locale' => $this->getLocale()
));
For now, I loop on theses results and unset all inactive Photos... but I'd like a clean way to do in the QueryBuilder.
I also tried to put the conditions on the LEFT JOIN clause :
->leftJoin('photo.translations', 'phototTranslation', Doctrine\ORM\Query\Expr\JOIN::WITH, 'photoTranslation.locale = :locale AND photoTranslation.active = :active')
But it always returns the Photo, even if it's inactive.
For this problem a solution may be:
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder();
$qb
->select('p', 'pp')
->from('Product', 'p')
->leftJoin('p.photos', 'pp')
->leftJoin('pp.translations', 'ppt', Doctrine\ORM\Query\Expr\Join::WITH, $qb->expr()->andX(
$qb->expr()->eq('ppt.locale', ':locale'),
$qb->expr()->eq('ppt.active', ':active')
))
->where('p.id', ':productId')
->setParameters(
array(
'productId', $productId,
'active', $active,
'locale', $locale
)
);
$query = $qb->getQuery();
return $query->getResult(); // or ->getSingleResult();
NOTE: this example is the way to do it in Symfony2 (2.3) entity repository