How to Write a SQL Query to Display list of most used tags in the last 30 days in Wordpress website - sql

I am looking for a way to display the most used tags over the last 30 days on my Baseball blog, built on Wordpress. I am no coder, but I have come up with this mashup to display a list of the most used 28 tags (preference to fit my theme). I cannot, for the life of me, figure out how to limit the tags to the most used in the last 30 days.
Here is what I have:
<ul id="footer-tags">
<?php
global $wpdb;
$term_ids = $wpdb->get_col("
SELECT DISTINCT term_taxonomy_id FROM $wpdb->term_relationships
INNER JOIN $wpdb->posts ON $wpdb->posts.ID = object_id
WHERE DATE_SUB(CURDATE(), INTERVAL 30 DAY) <= $wpdb->posts.post_date");
if(count($term_ids) > 0){
$tags = get_tags(array(
'orderby' => 'count',
'order' => 'DESC',
'number' => 28,
'include' => $term_ids,
));
foreach ( (array) $tags as $tag ) {
echo '<li>' . $tag->name . '</li>';
}
}
?>
</ul>
The website is slightly less than ~4 weeks old, so to test, I changed INTERVAL 30 DAY to INTERVAL 3 DAY and the tags being returned seem random and some haven't been used in 2+ weeks and have only been used a single time. As well, only 8 tags are being displayed, when more have been used.
To check that the correct number of days have been queried, I did the following:
Completely deleted all items in the trash for posts and pages, I don't have any custom post types.
Did the same with drafts.
Ran a query in phpmyadmin to delete all post revisions - DELETE FROM wp_posts WHERE post_type = "revision";
Ran a query in phpmyadmin to check if the results are the posts from the last 3 days - SELECT * from wp_posts WHERE DATE_SUB(CURDATE(), INTERVAL 3 DAY) <= post_date
The results from the phpmyadmin query were, in fact, the posts from the last 3 days, but the front-end display did not change.
UPDATE
Here are some screen shots. Maybe the screenshots can help find where my code is wrong.
Blog Post with Category and Tags
wp_posts table with the post ID of above post
wp_terms table with the term_id of the tags used
wp_term_taxonomy with the tags' term_id as term_taxonomy_id
wp_term_relationships with term_taxonomy_id assigned to post as object_id
UPDATE 2
I think I figured out the problem, but do not know how to fix it.
The SQL query gets the term_taxonomy_id, not the actual tag ID and get_tag_link uses term_id
UPDATE 3
I have recently created a plugin to display the most popular recently used tags - https://wordpress.org/plugins/recent-popular-tags/

The PHP variables you are inserting in your SQL string are the PHP objects that can be used to access WordPress tables from within PHP; whereas you are after the names of the tables and columns for accessing the data from within SQL.
You want instead:
"SELECT DISTINCT term_taxonomy_id FROM wp_term_relationships
INNER JOIN wp_posts ON wp_posts.ID = wp_term_relationships.object_id
WHERE DATE_SUB(CURDATE(), INTERVAL 30 DAY) <= wp_posts.post_date"
As an aside: should you ever need to insert the value of a PHP variable into a SQL statement, be very careful to escape it first in order to prevent any malicious code from being injected.

The problem was that the SQL query code was getting the term_taxonomy_id, not the actual tag ID.
I added an additional INNER JOIN using the term_taxonomy table to get the term_id. This seems to work, but if a mod can improve this, please do!
<ul id="footer-tags">
<?php $wpdb->show_errors(); ?>
<?php
global $wpdb;
$term_ids = $wpdb->get_col("
SELECT term_id FROM $wpdb->term_taxonomy
INNER JOIN $wpdb->term_relationships ON $wpdb->term_taxonomy.term_taxonomy_id=$wpdb->term_relationships.term_taxonomy_id
INNER JOIN $wpdb->posts ON $wpdb->posts.ID = $wpdb->term_relationships.object_id
WHERE DATE_SUB(CURDATE(), INTERVAL 30 DAY) <= $wpdb->posts.post_date");
if(count($term_ids) > 0){
$tags = get_tags(array(
'orderby' => 'count',
'order' => 'DESC',
'number' => 28,
'include' => $term_ids,
));
foreach ( (array) $tags as $tag ) {
echo '<li>' . $tag->name . '</li>';
}
}
?>
</ul>
UPDATE
I have recently created a plugin to display the most popular recently used tags - https://wordpress.org/plugins/recent-popular-tags/

Related

Prestashop module SQL Query to get id_products from a specific feature value

I'm currently working with a module called "Leo Parts Filter" on prestashop, which sort id_products by make, model, year and device in a database "ps_leopartsfilter_product".
When i call a make, model, year a device that have an id_product in this table, prestashop show this id_product.
public static $definition = array(
'table' => 'leopartsfilter_product',
'primary' => 'id_product',
'multilang' => false,
$sql = 'SELECT * FROM `' . _DB_PREFIX_ . 'leopartsfilter_product` WHERE 1=1 ';
if ($id_product != null && (int) $id_product) {
$sql .= ' AND id_product =' . (int) id_product;
}
I would like to change the way id_product is called, instead of calling only this id_product according this way :
I would like to query all products where the feature_id = 212 and where the feature_value_lang = id_product.
I tried to adapt this query but i can't make it work correctly (no data showing)
SELECT id_product, fl.name, value, pf.id_feature
FROM '._DB_PREFIX_.'feature_product pf
LEFT JOIN '._DB_PREFIX_.'feature_lang fl ON (fl.id_feature =212 AND fl.id_lang = '.(int)$context->language->id.')
LEFT JOIN '._DB_PREFIX_.'feature_value_lang fvl ON (fvl.id_feature_value = pf.id_feature_value AND fvl.id_lang = '.(int)$context->language->id.')
LEFT JOIN '._DB_PREFIX_.'feature f ON (f.id_feature = pf.id_feature)
'.Shop::addSqlAssociation('feature', 'f').'
WHERE fvl.`value` = '['id_product']'
GROUP BY id_product
ORDER BY f.position ASC
';
I'm not good at SQL so don't blame me, i learned everything by my way and i try to build my own company website, this module is all i need to finish.
If someone want some money for help, i'm open to give rewards to make it work.
Thanks
Your second query has nothing to do with the Leo Parts Filter module, since it only queries native Prestashop feature tables and not those of the Leo module itself, so your request is not very clear.
If you need to rely on basic features, it must be clear to you that the relationship between id features / id feature values and id products is all in the ps_feature_product table, so if you want products that have id_feature_value = 212 you just need a simple
SELECT id_product FROM ps_feature_product WHERE id_feature_value = 212;

Cakephp query to get last single field data from multi user

I have a table called Transaction with relation User, Transaction has a field called balance.
Data looks like:
id user_id balance
1 22 365
2 22 15
3 22 900
4 32 100
4 32 50
I need all users associative data and last insert balance field of User. For example here id=3 is last inserted data for user_id=22.
In raw SQL I have tried this:
select * from transactions where id in (select max(id) from transactions group by user_id)
If I add here a inner join I know I can also retrieve User data. But how can I do this in CakePHP?
IMHO, subqueries are ugly in CakePHP 2.x. You may as well hard code the SQL statement and execute it through query(), as suggested by #AgRizzo in the comments.
However, when it comes to retrieving the last (largest, oldest, etc.) item in a group, there is a more elegant solution.
In this SQL Fiddle, I've applied the technique described in
Retrieving the last record in each group
The CakePHP 2.x equivalent would be:
$this->Transaction->contains('User');
$options['fields'] = array("User.id", "User.name", "Transaction.balance");
$options['joins'] = array(
array('table' => 'transactions',
'alias' => 'Transaction2',
'type' => 'LEFT',
'conditions' => array(
'Transaction2.user_id = Transaction2.user_id',
'Transaction.id < Transaction2.id'
)
),
);
$options['conditions'] = array("Transaction2.id IS NULL");
$transactions=$this->Transaction->find('all', $options);

ZF2 how to avoid sql query limit to add quotes in subquery

I'm trying to set up a subquery in ZendFramework 2 and I got an issue with the limit function for a Select object. Whatever I do, numeric value is put between quotes and makes my query fails : I should get LIMIT 1 and instead I get LIMIT '1'.
Seems this is not the first time this issue has been encountered, I saw some have asked about this issue before (like 8 months ago) but without getting any proper answer.
I also saw this issue has been marker as resolved in 2012 (https://github.com/zendframework/zf2/pull/2775) so I really don't understand what's happening there.
Here's my code in ZF2 :
$resultSet = $this->tableGateway->select( function (Select $select) use ($params) {
$sub = new Select();
$sub->from(array('temp' => 'scores'))
->columns(array(new \Zend\Db\Sql\Expression("id AS id")))
->where(array('temp.glitch' => array('None', 'Glitch')))
->where('temp.zone=scores.zone')
->order('temp.multi DESC, temp.score DESC')
->limit(1);
$select->join('players', 'player=players.id', array('player_name' => 'name', 'player_url' => 'name_url'))
->join('countries', 'players.country=countries.id', array('country_name' => 'name', 'country_iso' => 'iso'))
->join('cars', 'car=cars.id', array('car_name' => 'name'), 'left')
->join('zones', 'zone=zones.id', array('zone_name' => 'name'));
$select->where(array('scores.id' => $sub));
$select->order('scores.zone ASC');
print_r($select->getSqlString());
});
This should render the following query (which I get right except LIMIT '1' instead of LIMIT 1) :
SELECT "scores".*, "players"."name" AS "player_name", "players"."name_url" AS "player_url", "countries"."name" AS "country_name", "countries"."iso" AS "country_iso", "cars"."name" AS "car_name", "zones"."name" AS "zone_name"
FROM "scores" INNER JOIN "players" ON "player"="players"."id"
INNER JOIN "countries" ON "players"."country"="countries"."id"
LEFT JOIN "cars" ON "car"="cars"."id"
INNER JOIN "zones" ON "zone"="zones"."id"
WHERE "scores"."id" = (SELECT id AS id FROM "scores" AS "temp" WHERE "temp"."glitch" IN ('None', 'Glitch')
AND temp.zone=scores.zone ORDER BY "temp"."multi" DESC, "temp"."score" DESC LIMIT 1)
ORDER BY "scores"."zone" ASC
Since this doesn't seem to work this way, is there another way I could proceed to get my limit (using Mysql 5 database) ?
EDIT :
Thanks for your help. Finally I figured out a way to get things done the way I want and to remove the quotes by simply remove the subquery construction and to write it directly in the where function :
$select->where('scores.id = (SELECT id FROM scores AS lookup WHERE lookup.zone = scores.zone ORDER BY multi DESC , score DESC LIMIT 1)');
Although I can continue my dev with this, I feel more like using a poor trick to get rid of this issue and so I will let this question unanswered until someone comes with a real solution there.
Anyway there might be no solution at all, since it might be an issue in ZF2 core itself.
Change the line -
$select->where(array('scores.id' => $sub));
with
$select->where(array('scores.id' => new \Zend\Db\Sql\Expression("({$sub->getSqlString($this->tableGateway->adapter->getPlatform())})"));
Try with just above change.
And if it still doesn't work then make changes to the core Select class file located at -
PROJECT_FOLDER/vendor/zendframework/zendframework/library/Zend/Db/Sql/Select.php
Line No. 921 -
Change $sql = $platform->quoteValue($limit); with $sql = $limit;
Line No. 940 -
Change return array($platform->quoteValue($offset)); with return array($offset);
I have come across the issue from github and wondered as why it is still not working with the latest ZF2 files. I know the solution given above doesn't look like the proper one but I had to somehow make it work. I have tried it and it works.
Its only a quick fix before the actual solution comes into picture.

Yii order by another table CActiveDataProvider

I am a bit stumped on this. Basically I have two tables:
Page:
id
name
Points:
id-
pageid
points
I am looking to get the records from the Page table, and sort it by the amount of points it has in the Points table (the points field)
Currently I have:
$dataProvider=new CActiveDataProvider('Page',array(
'criteria'=>array(
'condition'=>"active = 1 AND userid IN (".$ids.")",
'order'=>"???",
),
'pagination'=>array(
'pageSize'=>30,
),
));
I just don't know how to sort it by the Points table value for the relevant record
I have set up a relation for the Page/Points tables like so:
(in the Page model)
'pagepoints' => array(self::HAS_ONE, 'Points', 'pageid'),
Thanks
You need to do two things:
Add the pagepoints relation to the with part of the query criteria
Reference the column you want to sort by in the order part of the criteria
I 've marked the lines where this happens in the code below:
$dataProvider = new CActiveDataProvider('Page', array(
'criteria'=>array(
'with' => array('pagepoints'), // #1
'condition' => 'active = 1 AND userid IN ('.$ids.')',
'order' => 'pagepoints.points', // #2
),
'pagination'=>array(
'pageSize'=>30,
),
));
What you need to know to understand how this works is that when Yii builds the SQL query (which is a LEFT OUTER JOIN to the Points table), it uses the name you gave to the relation in the Page model (you give the definition for this, it's pagepoints) to alias the joined table. In other words, the query looks like:
SELECT ... FROM Page ... LEFT OUTER JOIN `Points` `pagepoints` ...
It follows that the correct specification for the sort order is pagepoints.points: pagepoints is the table alias, and points is the column in that table.
Try the following
$dataProvider=new CActiveDataProvider('Page',array(
'criteria'=>array(
'with'=>array('pagepoints'),
'condition'=>"active = 1 AND userid IN (".$ids.")",
'order'=>"t.points DESC",
),
'pagination'=>array(
'pageSize'=>30,
),
));
this is the sql you want to generate:
select * from page inner join points
on page.id = points.page_id order by
points.points desc

Wordpress latest Posts AND comments feed?

I'm trying to write a custom SQL query that will create a list of the most recent Posts AND comments and I'm having trouble visualizing how i can do this.
I can pull the latest comments by date DESC and i can pull the latest posts by date DESC but how do I make a feed / query to show them both?
Here is my comment SQL
SELECT comment_id, comment_content, comment_date
FROM wp_comments
WHERE comment_author = 'admin'
ORDER BY comment_date DESC
Edit: more clear:
Sorry, I should have been a little more clear. I want to have a list like this based on what date they occurred:
Wordpress post
wordpress post
wordpress comment
wordpress post
wordpress comment
So if someone comments on a 4 month old post, it will still show up at the top of this 'feed'
To get a list based solely on the most recent timestamp from two tables, you need to use a UNION:
SELECT wc.comment_date AS dt
FROM WP_COMMENTS wc
UNION ALL
SELECT wp.post_date AS dt
FROM WP_POSTS wp
ORDER BY dt
...where dt is the column alias for the column that holds the date value for records in either table.
Use UNION ALL - because data is from two different tables, there's no change of duplicates to filter out. But that means you have to get the other columns you want from either table to line up based on data and data type...
I think your best bet (and to avoid using custom SQL) would be to grab the latest X posts and X comments, loop over each and build an array to merge the two into one 'most recent' data set;
$comments = get_comments('number=X');
$posts = get_posts('posts_per_page=X');
$most_recent = array();
foreach ($comments as $comment)
$most_recent[strtotime($comment->comment_date_gmt)] = $comment;
foreach ($posts as $post)
$most_recent[strtotime($post->post_date_gmt)] = $post;
unset($comments, $posts);
krsort($most_recent);
$most_recent = array_slice($most_recent, 0, X);
foreach ($most_recent as $post_or_comment) {
$is_post = isset($post_or_comment->post_date_gmt);
// output comments and posts
}
It ain't too pretty, but it should do it.
No special mySql necessary, just use the query_posts loop and the get_comments function in the loop.
<?php query_posts('posts_per_page=10'); while (have_posts()) : the_post(); ?>
<div>
<a href="<?php the_permalink() ?>" title="Permanent Link to <?php the_title_attribute(); ?>"<?php the_title_attribute(); ?></a>
<?php echo the_title(); ?>
<?php
$comments = get_comments();
foreach($comments as $comm) :
echo($comm->comment_author);
echo($comm->comment_content);
endforeach;
?>
</div>
<?php endwhile; ?>