Minimising Database Queries in Wordpress when using Advanced Custom Fields - mysql

I'm working on a page which lists staff members for a large company and trying to minimise the number of times I'm forced to query the database as it gets quite complex and slow.
'person' is a custom post type (there are about 300 people)
'date_accredited' is a date field added via Advanced Custom Fields plugin.
Only accredited staff will have a 'date_accredited'.
I need to list every 'person' BUT, with ALL accredited staff listed first (so about 20 accredited staff come at the top).
At the moment, I am doing a call to WP_Query like:
$args = array(
'posts_per_page' => -1,
'post_type' => 'people',
'no_found_rows' => true,
'meta_key' => 'date_accredited'
);
$people = new WP_Query($args);
After that I'm doing:
while($people->have_posts()): $people->the_post();
$my_post_meta = get_post_meta($post->ID, 'date_accredited', true);
if (!empty($my_post_meta)) {
array_push($accredited, $post);
} else {
array_push($notAccredited, $post);
}
endwhile;
Leaving us with two arrays of 'person' objects. My thinking here was that I would be able to do something like the following to get the list I want:
foreach($accredited as $person):
personTile($person);
endforeach;
foreach($notAccredited as $person):
personTile($person);
endforeach;
I'm trying to avoid re-querying the database.
The personTile(); function was supposed to output various info and HTML (the_post_thumbnail() and various Advanced Custom Fields fields), but what I'm realising now is that none of this is included in the post objects I get from WP_Query(), so I'm forced to use things like:
get_the_post_thumbnail($person->ID)
get_permalink($person->ID)
get_field('date_accredited', $person->ID)
All of these cost another DB Query (each!), and worse still since they are in a loop each one happens around 300 times.
Is there any way to get the permalink, thumbnail and ACF fields to be included in the original DB Query? Would I need to resort to a custom MySQL Query???
Any other suggestions welcome!

Related

How can I have the name of my entity instead of the id in the related tables

I'm creating a project on CakePHP 3.x where I'm quite new. I'm having trouble with the hasMany related tables to get the name of my entities instead of their ids.
I'm coming from CakePHP 2.x where I used an App::import('controller', array('Users') but in the view to retrieve all data to display instead of the ids, which is said to be a bad practice. And I wouldn't like to have any code violation in my new code. Can anybody help me? here is the code :
public function view($id = null)
{
$this->loadModel('Users');
$relatedUser = $this->Users->find()
->select(['Users.id', 'Users.email'])
->where(['Users.id'=>$id]);
$program = $this->Programs->get($id, [
'contain' => ['Users', 'ProgramSteps', 'Workshops']
]);
$this->set(compact('program', 'users'));
$this->set('_serialize', ['ast', 'relatedUser']);
}
I expect to get the user's email in the relatedUsers of the program table but the actual output is:
Notice (8): Trying to get property 'user_email' of non-object [APP/Template\Asts\view.ctp, line 601].
Really need help
Thank you in advance.
You've asked it to serialize the relatedUser variable, but that's for JSON and XML views. You haven't actually set the relatedUser variable for the view:
$this->set(compact('program', 'users', 'relatedUser'));
Also, you're setting the $users variable here, but it's never been initialized.
In addition to #Greg's answers, the variable $relateduser is still a query object, meaning that trying to access the email property will fail. The query still needs to be executed first.
You can change the query to:
$relatedUser = $this->Users->find()
->select(['Users.id', 'Users.email'])
->where(['Users.id' => $id])
->first();
Now the query is executed and the only the first entry is returned.
There is are a number of ways to get a query to execute, a lot of them are implicit is use. See:
Cookbook > Retrieving Data & Results Sets

How to insert multiple rows into mysql using Codeigniter Rest Api

I have a form with one add button. Next row will append whenever i click on add button and all entered data should store into database. I can do for single record but unable to do with multiple records. Please provide any help for my issue. Thanks in advance.
$this->db->insert_batch() is used for bulk insert.
Example of how it works (assuming I have a series of 20 records to insert) :
array_push($newRecords, array(
"property1" => 1
"property2" => "two"
));
//...
array_push($newRecords, array(
"property1" => 20
"property2" => "twenty"
));
$this->db->insert_batch("tableName", $newRecords);
There are two different ways to do this:
you can put insert code in foreach
foreach($variable as $key=>$value){
$this->db->insert('table name',array('fieldname'=>'values'));
}
this above method called every time for every loop
or used the batch methods
$this->db->insert_batch('table name',$dataArray);
this above method will called one time only.

Magento - entered data into wrong fields

We did something wrong when uploading our products to our database. SKU number ended up in description, and description ended up in SKU.
It is around 1.000 products, so manually doing this is not an option. Also, this is an old error that didnt get noticed until now, so many of the products have order history on them by now.
Is there a way to switch these fields?
Try to identify the product ids that have this problem.
If all of them are in this situation that it's easier.
The idea is to first get an all the products that need modifying
If you can get them manually do this:
$ids = array(1,3,5,6,7,8, ...);
$products = Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect('description')->addAttributeToFilter('entity_id', $ids);
if all the products need modifying do this:
$products = Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect('description');
After you have all the ids run this script:
foreach ($products as $product) {
Mage::getSingleton('catalog/product_action')->updateAttributes(
array($product->getId()), //id to update
array( //values to update
'sku' => $product->getDescription(),
'description' => $product->getSku()
),
0 //store id
);
}

How to get return only specified fields with a find() / query

Currently I am using
$posts = $this->Post->find('all');
and it returns complete entries of the table posts but how can I get only partial entries. Some thing like
SELECT body,title FROM posts
Pass the "fields" option and specify (in an array) what fields you want to retrieve.
$posts = $this->Post->find('all', array(
'fields' => array('body', 'title')
));
I hate to be the guy that writes this, cause it usually bothers me, but I think this question is worth of "RTM".
This page in the book explains it all: http://book.cakephp.org/2.0/en/models/retrieving-your-data.html

WordPress Custom Select Query

I really don't know enough about MySQL queries and it's showing.
I have a custom field set for every post. The custom field stores the posts source URL in a key called "source_url".
I have it working with the below WP_Query parameters, but it's incredibly slow. Keep in mind it's possible to 50+ urls to search for.
So, given an array of source URL's, I want to fetch the matching posts.
For example, here is what I currently have that's slow in WP_Query:
// var_dump of $urls array (this could be 50+ urls)
array(7) {
[0]=>
string(42) "http://www.youtube.com/watch?v=FMghvnqDhT8"
[1]=>
string(42) "http://www.youtube.com/watch?v=RY-yUFpXTnM"
[2]=>
string(58) "http://www.youtube.com/watch?v=nIm2dnyJ1Ps&feature=related"
[3]=>
string(42) "http://www.youtube.com/watch?v=NoCtRQlJAqM"
[4]=>
string(57) "http://holidaycustoms.blogspot.com/2012/08/busy-week.html"
[5]=>
string(42) "http://www.youtube.com/watch?v=DcZvg197Ie4"
[6]=>
string(42) "http://www.youtube.com/watch?v=7P3UEbLmLuo"
}
// Build Media Query
$meta_query = array(
'relation' => 'OR'
);
foreach( $urls as $url ) {
$meta_query[] = array(
'key' => 'source_url',
'value' => $url
);
}
// Get 20 matching posts from a category set by a variable
$args = array(
'post_type' => 'post',
'posts_per_page' => 20,
'orderby' => 'rand',
'cat' => $cat_ID,
'meta_query' => $meta_query
);
$posts = get_posts($args);
What I'm looking to do is replace the above code with a custom query select, which I have read is much faster than WP_Query.
But I don't know enough about MySQL or the WP database to build the custom select query. Can anyone help? Thanks in advance!
In the post you linked yourself, the first reply already states that
[...] the default schema doesn't even have an index on the value column
Which is far more severe a problem than any you would have with a query generator, because without an index the DBMS has to traverse the whole table and compare strings of each field.
Adding an index is fairly easy with an appropriate management tool like PHPMyAdmin. The offending table you will need to add an index to is called wp_postmeta and the field that needs an index is meta_value, and the index type should be INDEX.
Adding an index is transparent and does not affect wordpress other than in performance. It could take some time though since, well MySQL needs to traverse the whole table. Also, because you are indexing string data, the index will be quite big.
You should also try using appropriate structures for your query. You are currently using a big ORed selection with different values but always the same field. There is a construct for just that, and it's called IN.
...
// Build Media Query
$meta_query = array();
$meta_query[] = array(
'key' => 'source_url',
'value' => $urls,
'compare' => 'IN'
);
// Get 20 matching posts from a category set by a variable
..
(Untested. I actually never did this, Reference)
The performance gain would be negligible compared to adding an index I assume, but your code would become a lot simpler.