Reading node field values in drupal7 programmatically - drupal

I am looking for the best way to get a field value from a node id.
My actually code works however I guess there is an easier way.
$node = node_load( 1 );
$lang = $node->language;
$field = 'body';
$value = '';
if ( isset($node->{$field}[$lang]) && isset($node->{$field}[$lang][0]) )
{
$value = $node->{$field}[$lang][0]['value'];
}
echo $value;
Is there any build in drupal function that takes care of this?

Not all of it, but you should be able to simplify it a bit with http://api.drupal.org/api/drupal/modules--field--field.module/function/field_get_items/7.
You still need to check if $items[0] exists and get the 'value' of that.

Thanks #Berdir. I agree field_get_items is a better way. Here is a code example:
<?php
$body = field_get_items('node',$node, 'body');
print $body[0]['value'];
?>

Related

Custom Taxonomies and how to stay in them when the posts have multiple terms selected?

Wondering if anyone can help me think this one out?
Whilst in lock-down, I've been putting together a simple site to organise my collection of Retro Gaming Adverts covering systems from the Atari 2600 up to the N64. I've still got a few 1000 to add to the site (takes time) but i've come across an issue I'm not sure how to implement a fix for.
You can browse the adverts by system through their single post pages but if an advert covers multiple systems it messes up the previous and next posts link and will drop you into another system.
For Example: If you're using the next and previous post links to go through the "mega drive / genesis" section once you get to " Battletoads and Double Dragon " when you press the next post arrow this time you're suddenly going through adverts tagged as NES, due to the fact thats the first term associated with it.
See : https://www.retrogameads.com/system/mega-drive/ and click on the first advert, then keep pressing the next arrow and you'll see what i mean.
I guess I could post each advert multiple times for each system but I don't like the idea of that.
Anyone got any suggestions on how I could work out what Term the user was browsing and keep them in that one?
Bare in mind this site is a work in progress so the design is just something basic till i work out the best way to organise things.
Let me know your thoughts.
Update:
Current method for getting prev next posts...
<?php
$terms = get_the_terms( $post->ID, 'system' );
$i = 0;
$systems = array();
foreach ( $terms as $term ) {
$systems[$i] = $term->slug;
$i++;
}
$postlist_args = array(
'posts_per_page' => -1,
'post_type' => 'portfolio',
'system' => $systems[0],
'order' => 'ASC',
'orderby' => 'title'
);
$postlist = get_posts( $postlist_args );
$ids = array();
foreach ($postlist as $thepost) {
$ids[] = $thepost->ID;
}
$thisindex = array_search($post->ID, $ids);
$previd = $ids[$thisindex-1];
$nextid = $ids[$thisindex+1];
?>
<div class="prev_next">
<?php
if ( !empty($previd) ) {
echo '<div class="older"><a rel="prev" href="' . get_permalink($previd). '">‹</a></div>';
}
if ( !empty($nextid) ) {
echo '<div class="newer"><a rel="next" href="' . get_permalink($nextid). '">›</a></div>';
}
?>
When you click on an advert, you're essentially visiting the single page for that advert. At that moment, WP does not know/remember that the user only wants to see adverts from the system you clicked.
How are you rendering the previous/next links right now?
One possible solution could be to add a parameter to the URL and then take this into account in the PHP code when rendering the previous/next links. (/portfolio/advert-name/?system=mega-drive for example)
Edit: Of course the URL could also be made prettier... if you want to put in some extra work, you could register a permalink of the form /portfolio/mega-drive/advert-name/ for example. But this would require a bit more work.
Would that work? I think it would be the best solution considering the alternatives.
Update: For the actual implementation, the get_next_post_where and get_previous_post_where filters might prove to be very useful. You could make it so that it takes the system parameter into account for the previous/next links.
Another option: You could also set up a PHP session and remember the current system that way, but then you will require a PHP session, which is not a good thing, and it will also prevent you from using full page caching (performance optimization).
Yet another option would be to remember the current system client-side through a cookie. But in that case you have caching issues again unless you load the previous/next links through AJAX.
After reading the update on your question, I have the following notes:
system is not a valid argument and will be ignored on the get_posts() call.
the method you use to get the previous and next posts is very inefficient, because you query the whole database, and then you save everything in memory, and then you comb through the whole result set in memory, using a lot of unnecessary ram and CPU power
So how can we improve this?
Simple: Use the get_previous_post and get_next_post functions on the $post. It accepts three arguments. Here is the example for get_next_post (but get_previous_post is basically the same):
get_next_post( bool $in_same_term = false, array|string $excluded_terms = '', string $taxonomy = 'category' )
Now if you set $in_same_term to true then the next post will be of a post that shares at least one taxonomy term (system in our case).
You also have to set $taxonomy to system because that is the custom taxonomy.
And the other parameter is $excluded_terms. Too bad there is no $included_terms otherwise we could just put the system we want in there. But we can do it another way... We can filter out the current system (in the system GET parameter in our URL) and keep all other systems as systems to exclude.
So let's build what we need now.
global $post;
// What system did we come from?
$system = $_GET['system'] ?? null; // Set to null if nothing was specified (uses PHP's null coalescing operator available since PHP 7
// Exclude nothing by default
$excluded_term_ids = [];
// If we came here by clicking on a system, then exclude all other systems so the previous/next links will be of the same system only
if ($system) {
// Retrieve system terms for this post
$terms = get_the_terms( $post, 'system' );
// Filter the list of terms to remove the system we came from
// This way we can create a list of terms to exclude
$excluded_terms = array_filter( $terms, function ( $term ) use ( $system ) {
return $term->slug != $system;
} );
// The get_previous_post and get_next_post functions expect $excluded_terms to be an array of term IDs, so we must map the WP_Term objects into IDs
$excluded_term_ids = array_map( function ( $term ) {
return $term->term_id;
}, $excluded_terms );
}
// Retrieve previous and next post
$previous_post = $post->get_previous_post( true, $excluded_term_ids, 'system' );
$previous_post = $post->get_next_post( true, $excluded_term_ids, 'system' );
// Echo out the page links
// And don't forget to re-add the ?system= parameter to the URL
$url_suffix = $system ? ('?system=' . $system) : '';
if ( $previous_post ) {
echo '<div class="older"><a rel="prev" href="' . get_permalink($previous_post) . $url_suffix . '">‹</a></div>';
}
if ( $next_post ) {
echo '<div class="newer"><a rel="next" href="' . get_permalink($next_post) . $url_suffix . '">›</a></div>';
}
NOTE: Untested code.. So there might be a small bug somewhere.. Let me know if you encounter an issue with this code..
Important: On the page of a system, you must now also add '?system=current-system' to the URLs that you render.
Probably something like: echo get_permalink($advert) . '?system=' . $post->post_name (could be different depending on how your code is on that screen..)

Wordpress search database values and return

i'm have been searching for a code that will do some thing like this in WordPress and but it CANT call on woocommerce
nothing seems to work
if
get_post_meta( get_the_ID(), '_regular_price' is greater then 1)
do this
else
do this code
It depends on the place where you are using this function.
Imagine you are trying to edit a product page. In your woocommerce templates folder, you find for example: price.php
Usually there is one global variable available already, and if it's not available you can set it with global $product. With $product->get_id() you can get the product id then.
With the global variable the sale price is then available like this $price = $product->get_sale_price();
In order to make the if statement, you need the data so then the next step. Maybe your price is empty for some reason, which returns undefined, making it difficult to do the if statement
if (empty($price))
$price = 0;
if($price > 1))
// do your thing
$my_post_meta = get_post_meta( get_the_ID(), 'sale_price', true);
if ( ! empty ( $my_post_meta ) ) {
do code here
} else
do other code
this works for me

WP Rest API get post by slug with special characters (ex: !&')

I have posts with slugs with special characters. One of them is the following:
http://localhost/wp-json/wp/v2/posts?slug=my-post!
Unfortunately, WP REST API not showing the content since it has (!) within the slug.
Is there any solution you guys would recommend?
I have found the solution (at least for my case), not sure if it'll work for you but may indicate you the way to go. We need to tap into the function used to sanitize the slugs, as I said in my comment, by default is wp_parse_slug_list. Looking at the code the function that actually sanitizes the slug is sanitize_title.
Looking at the source code, wp_parse_slug_list calls sanitize_title with only one argument, which means that the context used is save. This means that, for posts that were already saved without being sanitized by this function, the slug won't match and the post will be inaccessible through the API. The solution is to change the sanitizing function slightly by adding a filter:
add_filter('rest_post_collection_params', function($query_params) {
$query_params['slug']['sanitize_callback'] = 'sanitize_rest_api_slug';
return $query_params;
}, 20, 1);
function sanitize_rest_api_slug( $list ) {
if ( ! is_array( $list ) ) {
$list = preg_split( '/[\s,]+/', $list );
}
foreach ( $list as $key => $value ) {
$list[ $key ] = sanitize_title( $value, '', 'query' );
}
return array_unique( $list );
}
The filter is actually being applied on the function get_collection_params() on the class-wp-rest-posts-controller class, but if you look at the source code, the filter has a variable depending on the post_type, so if you have another special kind of posts defined (besides post) you need to add/change a filter for that kind as well.
I hope this helps somebody else like me, even if it's too late for your issue.

How to get data from Wordpress database?

I am trying to get a row out of a table (gc_test) I created in my Wordpress database. I have read the Wordpress documentation and followed it exactly and still no joy.
The $results array never seems to get populated.
$results = $wpdb->get_row("SELECT * FROM $wpdb->gc_test WHERE coupon_code = $code, ARRAY_A");
if($results['redeemable']=="true"){
$message = "Code is good!";
}
else{
$message = "Code has already been redeemed!";
}
The way you are referring to your custom table is not correct. The correct way is to global $wpdb and the prefix property. The way that you have $code embedded is also not correct for a few reasons - it is likely a string and should be surrounded by single quotes, but no matter what is likely a potential SQL injection vulnerability. Make sure to use $wpdb->prepare() to pass arguments with placeholders of %s for strings and %d for digits. You also have the double quotes in the wrong place - it is including ARRAY_A in with your SQL rather than as an argument to get_rows().
// declare $wpdb.
global $wpdb;
// sql string using $wpdb->prefix and %s placeholder
$sql = "SELECT * FROM {$wpdb->prefix}gc_test WHERE coupon_code = %s";
// pass the sql into prepare()
$query = $wpdb->prepare( $sql, $coupon_code );
// call get_row() and tell it that you want an associative array back
$row = $wpdb->get_row( $query, ARRAY_A );
if ( empty( $row ) ){
// nothing came back from the db
$message = "Code not found.";
} elseif ( isset( $row['redeemable'] ) && $row['redeemable'] == "true" ){
// we got a row and it was redeemable
$message = "Code is good!";
} else {
// something else
$message = "Code has already been redeemed!";
}
Thanks to doublesharp's post I went back and studies the $wpdb->prefix function. Apparently this is pretty important. So I changed my prefix on the table from gc_ to wp_ and then assigned the table to a variable with: {$wpdb->prefix}test and it now works like a charm. Thanks a ton!

Edit site_url with filter

With WordPress, calling site_url() returns the full site URL (http://www.example.com)
What I'm trying to do is adding something (add-something-here) at the end of the URL with filter.
The result I'm expecting is:
http://www.example.com/add-something-here
Does someone know how to do that with filter?
I tried the following with no success:
function custom_site_url($url) {
return get_site_url('/add-something-here');
}
add_filter('site_url', 'custom_site_url');
The problem is that you are producing a loop with this filter. The function get_site_url is exactly where the filter site_url is being called.
You need:
add_filter( 'site_url', 'custom_site_url' );
function custom_site_url( $url )
{
if( is_admin() ) // you probably don't want this in admin side
return $url;
return $url .'/something';
}
Bear in mind, that this may produce errors for scripts that rely on the real URL.
Untested, but since it's PHP could you just try...
function custom_site_url($url) {
return get_site_url() . '/add-something-here';
}
add_filter('site_url', 'custom_site_url');
Untested, but this is a snippet of what I use often:
$constant = 'add-something-here';
return ''. esc_html( $name ).'';
or you might simply want to get the page ID instead and it's much better.
$page_id = '2014';
return '.esc_html__( 'pagename', 'text-domain' ).'

Resources