PHP Warning: Missing argument 2 for wpdb::prepare() WPML Plugin - php

Suddenly I am getting an error on a specific backend page on my wordpress project:
Warning: Missing argument 2 for wpdb::prepare(), called in .../wp-content/plugins/wpml-media/inc/wpml_media.class.php on line 463 and defined in .../wp-includes/wp-db.php on line 992
Which would be:
wpml_media.class.php
// get language of their parents
if(!empty($missing_langs)){
$results = $wpdb->get_results($wpdb->prepare("
SELECT p.ID, t.language_code
FROM {$wpdb->posts} p JOIN {$wpdb->prefix}icl_translations t ON p.ID = t.element_id AND t.element_type = CONCAT('post_', p.post_type)
WHERE p.ID IN(".join(',', $missing_langs).")
"));
foreach($results as $row){
$parent_langs[$row->ID] = $row->language_code;
}
}
and wp-db.php
function prepare( $query, $args ) {
if ( is_null( $query ) )
return;
$args = func_get_args();
array_shift( $args );
// If args were passed as an array (as in vsprintf), move them up
if ( isset( $args[0] ) && is_array($args[0]) )
$args = $args[0];
$query = str_replace( "'%s'", '%s', $query ); // in case someone mistakenly already singlequoted it
$query = str_replace( '"%s"', '%s', $query ); // doublequote unquoting
$query = preg_replace( '|(?<!%)%f|' , '%F', $query ); // Force floats to be locale unaware
$query = preg_replace( '|(?<!%)%s|', "'%s'", $query ); // quote the strings, avoiding escaped strings like %%s
array_walk( $args, array( $this, 'escape_by_ref' ) );
return #vsprintf( $query, $args );
}
I have no clue whats happening here, any ideas? Unfortunately the author's support has expired.
Thanks

$wpdb->prepare needs at least two params http://codex.wordpress.org/Class_Reference/wpdb#Protect_Queries_Against_SQL_Injection_Attacks
try something like that:
$wpdb->prepare("
SELECT p.ID, t.language_code
FROM {$wpdb->posts} p JOIN {$wpdb->prefix}icl_translations t ON p.ID = t.element_id AND t.element_type = CONCAT('post_', p.post_type)
WHERE p.ID IN(%s)", join(',', $missing_langs))

There's some more info on this problem here. Basically, don't panic because it's just a warning so nothing is going to actually break.
If you're looking to modify the wpml-media plugin to get rid of this error, the developer info in the above link should help. If you just want the warning to go away, then I quote:
First, if you’re a user and you want to get rid of these errors, you should turn off the displaying of errors in PHP. There are many ways to do this, such as in php.ini, .htaccess, etc. For this, you can just put this in wp-config.php. (Note that hiding errors on production sites is good practice anyway.)
#ini_set('display_errors', 0);

Related

Improve Performance get_post_meta WordPress

I created a logic inside my WordPress, where for every CPT shop_oder, there is a post_meta called "luck_number". The problem is that on average, each post in this CPT has had more than 1000 sales, and then when I create a while to go through and get the post_meta with get_post_meta, the page takes about 15 minutes to load, specifically inside the While do loop.
I did a test, and when there are few post_meta the speed is ok, but when we get to the thousand place, it gets pretty slow.
What would be the best way, so that even in this scenario of thousands of post_meta per POST, I still have a good performance?
The section where the laugh is like this:
<?php
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
$numbers = get_post_meta(get_the_ID(),"luck_number",false);
$a = 0;
while($a<count($numbers)):
// DO SOMETHING WITH THE NUMBER
$a++;
endwhile;
endwhile;
wp_reset_query();
While each post has an average of 0 to 500 numbers, everything works fine. Above 1000, it's very slow.
My 'post_per_page' averages 25, but even changing it to a smaller number doesn't change the result much. The infrastructure like the server (a good VPS) or the memory_limit of PHP (currently with 1024M) hasn't interfered much
If you need only one custom_field from CPT, you don't need to use WP_Query
You can just take all fields in the array through $wpdb
Try this code
function get_luck_numbers_from_db( $key = '', $type = 'post', $status = 'publish' ) {
global $wpdb;
if( empty( $key ) )
return;
$r = $wpdb->get_results( $wpdb->prepare( "
SELECT pm.post_id, pm.meta_value FROM {$wpdb->postmeta} pm
LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
WHERE pm.meta_key = '%s'
AND p.post_status = '%s'
AND p.post_type = '%s'
", $key, $status, $type ) );
foreach($r as $value) {
if($value !="") {
$luck_numbers_array[$value->post_id] = $value->meta_value;
}
}
return $luck_numbers_array;
}
$array = get_luck_numbers_from_db('luck_number','shop_oder', 'publish');
print_r($array);

PHP IF OR statement validation error

Im using the below code in order to add all Wordpress posts (excluding the 'sliders' category) to a category called 'Frontpage' ID = 28
function add_category_automatically1($post_ID) {
global $wpdb;
$postsWeWants = $wpdb->get_results("SELECT ID, post_author FROM $wpdb->posts where ID = $post_ID");
foreach ($postsWeWants as $postsWeWant) {
if (!in_category('sliders')) {
$cat = array(28, );
wp_set_object_terms($post_ID, $cat, 'category', true);
}
}
I want to add the exception of an additional category called 'business-information' but I can't get the OR operator to validate properly.
I was looking at using something like below
function add_category_automatically1($post_ID) {
global $wpdb;
$postsWeWants = $wpdb->get_results("SELECT ID, post_author FROM $wpdb->posts where ID = $post_ID");
foreach ($postsWeWants as $postsWeWant) {
if (!in_category('sliders')) OR (!in_category('business-information')) {
$cat = array(28, );
wp_set_object_terms($post_ID, $cat, 'category', true);
}
}
This:
if (!in_category('sliders')) OR (!in_category('business-information'))
// ^ -- ^ -- and here
is wrong. Because you close ) and open ( too early.
Proper code is:
if (!in_category('sliders') OR !in_category('business-information'))
And by the way such logic is invalid. If item is in 'business-information' then !in_category('sliders') true. I suppose you need to check for not existing in both cats:
if (!in_category('sliders') AND !in_category('business-information'))
You are using it wrong instead if (!in_category('sliders')) OR (!in_category('business-information')) {
write it like this (one more thing which is mentioned by #FirstOne you need to use AND instead OR to apply both conditions not one of them)
if( !in_category('sliders') AND !in_category('business-information') ) {
...
}
so that both !in_category checks will be in same if( ... ) scops

Wordpress query posts by title issue

I'm using below code to get posts by title.
protected function get_post_by_title($post_title, $output = OBJECT, $post_type = 'post' )
{
global $wpdb;
$post = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type= %s", $post_title, $post_type ));
if ( $post )
return get_page($post, $output);
return null;
}
Everything is working fine, except it will not find the posts having single quote in title. Consider below as $post_title.
This is a test's post
$wpdb->prepare will return query something like below.
This is a test\\\'s post
Which will return no result. Can anyone please help me on this ?
Thanks in advance
You should never compare with the real title. Wordpress offers you the possibility to create slugs without all those weird characters like " " or "'". Then you can compare them:
Use sanitize_title() to create a slug from your title, and then you can compare them.
I think this should fix the issue,
DOC: http://in1.php.net/manual/en/mysqli.real-escape-string.php
protected function get_post_by_title($post_title, $output = OBJECT, $post_type = 'post' )
{
global $wpdb;
$post_title = mysqli_real_escape_string($post_title); //escape special meaning
$post = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type= %s", $post_title, $post_type ));
if ( $post )
return get_page($post, $output);
return null;
}
edit:
That might not work, try this,
$post_title = addslashes($post_title);
Let me know which one works for you.

Need some PHP help for making a change to wordpress plugin Groups

I'm really in a jam here. I am extremely close to launching my wordpress site. I have one rather large obstacle in my way that should be an easy fix. I am beginner level php so I am really struggling on this and any help or direction would be extremely appreciated since I have been trying to solve this issue for two weeks through reading and research.
Here is the issue and I will try to be as detailed as possible:
I have a custom post type called Portfolio.
I have a Portfolio page where it loads all of the featured images of
the Portfolio Posts into a grid on the Portfolio Page. You know a
basic portfolio setup where if you click the image it takes you to
the portfolio post.
Using the Groups plugin, when I restrict access to a Portfolio Post,
it removes the featured image from the Portfolio Page grid. Like the
post doesn't exist for non group members.
I am trying to sell access to these Portfolio Posts so if someone is
not a member they will not know there is anything there to buy.
I don't know how to make it to where those featured images still show on the Portfolio Page. I need people to know they are there but not be able to access them. As I mentioned in the support question, I cannot use a shortcode for this because the video is hard coded in to my theme. I need to add it to the code in a custom plugin to change groups to not remove that featured image from my portfolio page regardless of the restriction on the post.
I have gone through the API and found the section that controls access to the restricted posts. The Class is Groups-Post-Access. When both of these are removed from the class-groups-access.php I am able to see the featured images on the Portfolio page but it also removes the function that restricts the actual post. I don't know how I could tell the plugin to only return the featured image but still hide access to the post.
add_filter( 'posts_where', array( __CLASS__, 'posts_where' ), 10, 2 );
/**
* Filters out posts that the user should not be able to access.
*
* #param string $where current where conditions
* #param WP_Query $query current query
* #return string modified $where
*/
public static function posts_where( $where, &$query ) {
global $wpdb;
$user_id = get_current_user_id();
// this only applies to logged in users
if ( $user_id ) {
// if administrators can override access, don't filter
if ( get_option( GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE, GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE_DEFAULT ) ) {
if ( user_can( $user_id, 'administrator' ) ) {
return $where;
}
}
}
// 1. Get all the capabilities that the user has, including those that are inherited:
$caps = array();
if ( $user = new Groups_User( $user_id ) ) {
$capabilities = $user->capabilities_deep;
if ( is_array( $capabilities ) ) {
foreach ( $capabilities as $capability ) {
$caps[] = "'". $capability . "'";
}
}
}
if ( count( $caps ) > 0 ) {
$caps = implode( ',', $caps );
} else {
$caps = '\'\'';
}
// 2. Filter the posts that require a capability that the user doesn't
// have, or in other words: exclude posts that the user must NOT access:
// The following is not correct in that it requires the user to have ALL capabilities:
// $where .= sprintf(
// " AND {$wpdb->posts}.ID NOT IN (SELECT DISTINCT ID FROM $wpdb->posts LEFT JOIN $wpdb->postmeta on {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id WHERE {$wpdb->postmeta}.meta_key = '%s' AND {$wpdb->postmeta}.meta_value NOT IN (%s) ) ",
// self::POSTMETA_PREFIX . self::READ_POST_CAPABILITY,
// $caps
// );
// This allows the user to access posts where the posts are not restricted or where
// the user has ANY of the capabilities:
$where .= sprintf(
" AND {$wpdb->posts}.ID IN " .
" ( " .
" SELECT ID FROM $wpdb->posts WHERE ID NOT IN ( SELECT post_id FROM $wpdb->postmeta WHERE {$wpdb->postmeta}.meta_key = '%s' ) " . // posts without access restriction
" UNION ALL " . // we don't care about duplicates here, just make it quick
" SELECT post_id AS ID FROM $wpdb->postmeta WHERE {$wpdb->postmeta}.meta_key = '%s' AND {$wpdb->postmeta}.meta_value IN (%s) " . // posts that require any capability the user has
" ) ",
self::POSTMETA_PREFIX . self::READ_POST_CAPABILITY,
self::POSTMETA_PREFIX . self::READ_POST_CAPABILITY,
$caps
);
return $where;
}
add_filter( 'the_posts', array( __CLASS__, "the_posts" ), 1, 2 );
/**
* Filter posts by access capability.
*
* #param array $posts list of posts
* #param WP_Query $query
*/
public static function the_posts( $posts, &$query ) {
$result = array();
$user_id = get_current_user_id();
foreach ( $posts as $post ) {
if ( self::user_can_read_post( $post->ID, $user_id ) ) {
$result[] = $post;
}
}
return $result;
}
If someone can give me a better understanding of what is happening here and maybe an example of what he is referring to by creating a template for my custom post type, I would really appreciate it. Thank you so much for your time!
This was solved by using wordpress to handle hiding a specific category vs changing the actual plugin code.

How to skip certain links on adjacent posts in Wordpress?

I use the following code to fetch the links of the previous and next posts respectively, from the single post template;
<?php echo get_permalink(get_adjacent_post(false,'',false)); ?>
<?php echo get_permalink(get_adjacent_post(false,'',true)); ?>
My question is, please, if there are certain posts I'd like these codes to skip, and simply go to the ones right after, could I do that somehow using custom fields, or otherwise how can I make Wordpress skip a certain link when it comes up and fetch the next adjacent one without first going to the one I'd like to skip and then redirect or something, but rather echo the correct one right away..?
Thank you very much!
Alex
You can approach this in different ways. The easiest solution would probably be to use an "excluded category" (second parameter), e.g. exclude posts from category with term ID 5:
get_adjacent_post( false, '5', false )
Another option is to use the get_previous_post_where and get_next_post_where filters to modify the SQL query.
You could store in the options table an array of post IDs to be excluded, here's an example how you could exclude all sticky posts:
add_filter( 'get_previous_post_where', 'so16495117_mod_adjacent' );
add_filter( 'get_next_post_where', 'so16495117_mod_adjacent' );
function so16495117_mod_adjacent( $where ) {
return $where . ' AND p.ID NOT IN (' . implode( ',', get_option( 'sticky_posts' ) ) . ' )';
}
Or, as you suggested in your Q, you could filter out posts that have a certain post meta key, e.g. my_field:
add_filter( 'get_previous_post_where', 'so16495117_mod_adjacent_bis' );
add_filter( 'get_next_post_where', 'so16495117_mod_adjacent_bis' );
function so16495117_mod_adjacent_bis( $where ) {
global $wpdb;
return $where . " AND p.ID NOT IN ( SELECT post_id FROM $wpdb->postmeta WHERE ($wpdb->postmeta.post_id = p.ID ) AND $wpdb->postmeta.meta_key = 'my_field' )";
}

Categories