I have a custom wordpress php rest api. The API has 2 functions. The first function is returning all posts from the wordpress website. Second function is returning posts by slug.
I have developing mobile app for the website(blog website). I am getting datas for the app.
And I have some anxiety here. I am getting a lot of datas about articles and one of these is article Id.
The question: Is it logical to get wordpress article id with php api. I am asking for security.
1-The api is my custom api for get datas about article.
2-If I don't use the custom php api, I will use the mysql database for save the article informations. And I will get the article datas with php api. But I will set my own id for article(I won't use the wordpress article id).
Which one is the best way to use. Please think for security.
This is my custom PHP API function.
function api_posts()
{
$args = [
'numberposts' => 99999,
'post_type' => 'post',
];
$posts = get_posts($args);
$data = [];
$i = 0;
foreach ($posts as $post) {
$category = get_the_category( $post->ID )[0]->name;
$data[$i]['category'] = $category;
$data[$i]['id'] = $post->ID;
$data[$i]['title'] = $post->post_title;
$data[$i]['excerpt'] = $post->post_excerpt;
$data[$i]['content'] = $post->post_content;
$data[$i]['slug'] = $post->post_name;
// $data[$i]['featured_image']['thumbnail'] = get_the_post_thumbnail_url($post->ID, 'thumbnail');
$data[$i]['thumbnailImage'] = get_the_post_thumbnail_url($post->ID, 'thumbnail');
$data[$i]['mediumImage'] = get_the_post_thumbnail_url($post->ID, 'medium');
$data[$i]['largeImage'] = get_the_post_thumbnail_url($post->ID, 'large');
setlocale(LC_TIME, array('tr_TR.UTF-8','tr_TR.UTF-8','tr_TR.UTF-8','tr_TR.UTF-8'));//tarihi esas alan locali seçer
$gelen_date = $post->post_date;
$data[$i]['date'] = strftime("%e %B %Y",strtotime($gelen_date));
$data[$i]['post_url'] = get_permalink($post->ID);
$i++;
}
return $data;
}
add_action('rest_api_init', function () {
register_rest_route('api/v1', 'posts', [
'methods' => 'GET',
'callback' => 'api_posts',
]);
register_rest_route('api/v1', 'posts/(?P<slug>[a-zA-Z0-9-]+)', array(
'methods' => 'GET',
'callback' => 'api_post',
));
});
Footnote: The website is not ready to publish. I am using free wordpress blog theme for the test. But I will use the jannah theme when I publish my website.
Post ID values are visible to visitors to a WordPress site. (They show up in places like HTML element classes. Do View Source on a page showing posts and you'll see this.)
So if your reason for using an alternative ID is to avoid disclosing post ID values (maybe for security reasons) don't bother. They are already available.
Plus, if you use an alternative ID you'll probably need to store it as a post attribute in wp_postmeta in your database. That is, putting it mildly, not the best-performing part of WordPress.
Related
I have an app for wordpress blog site. this app getting wordpress articles with php api call.
I am using this code for get article list.
function api_posts()
{
$args = [
'numberposts' => 99999,
'post_type' => 'post',
];
$posts = get_posts($args);
$data = [];
$i = 0;
foreach ($posts as $post) {
$data[$i]['id'] = $post->ID;
$data[$i]['title'] = $post->post_title;
$data[$i]['excerpt'] = $post->post_excerpt;
$data[$i]['content'] = $post->post_content;
$data[$i]['slug'] = $post->post_name;
$data[$i]['thumbnailImage'] = get_the_post_thumbnail_url($post->ID, 'thumbnail');
$data[$i]['mediumImage'] = get_the_post_thumbnail_url($post->ID, 'medium');
$data[$i]['largeImage'] = get_the_post_thumbnail_url($post->ID, 'large');
$data[$i]['date'] = $post->post_date;;
$data[$i]['post_url'] = get_permalink($post->ID);
$i++;
}
return $data;
}
I am getting ID, post_excerpt, post_content and others. So I am getting 10 information about one article. But I want to get more than 10 information about one artice. But I don' know the keys to get informations. For example I want to get article category. How can I do this. Where can I learn keys like post_title, post_excerpt. I know developers.wordpress but I don't understand it.
This is my custom wordpress api result
https://meshcurrent.online/wp/wp-json/api/v1/posts/
EDIT
Here's 1 more re-write but with a query as for some strange reason get_post_meta was not giving all the meta data as it used to before:
function api_posts(){
global $wpdb;
$posts_with_meta = $wpdb->get_results(
"SELECT *
FROM $wpdb->posts INNER JOIN $wpdb->postmeta
on $wpdb->posts.`ID` = $wpdb->postmeta.`post_id` where $wpdb->posts.`post_type` = 'post'
"
);
return $posts_with_meta;
}
OLD ANSWER
Here's how you can get all the meta keys and their values of all the posts:
function api_posts()
{
$args = [
'numberposts' => 99999,
'post_type' => 'post',
];
$posts = get_posts($args);
$data = [];
$i = 0;
foreach ($posts as $post) {
$allPostMeta = get_post_meta($post->ID);
foreach($allPostMeta as $key => $value) {
$data[$i][$key] = $value[0];
}
$i++;
}
return $data;
}
I've just done a re-write of your code to get you all the keys with their data. I can't test or replicate it as it's specific to your environment but I'm sure it'll work just fine for you.
Some keys might differ for your blog app and the website WordPress it's called post_title but your app reads it as the title. You'll need to work around that. But this will pretty much give you a list of all meta keys applicable to a post and you can then play around with your code and add only those keys which you need.
Once you know the fields you want in the API, You must also checkout WP_QUERY as that is more powerful and has a fields filter which can give you only those fields that you need for the app and not push all the data. Thus, saving API response time.
I hope this will help you.
I don't think there is any function available to return all data. You'll have to collect all the data manually.
If you're interested in getting categories and tags then you'll have to use wp_get_post_terms function to get the terms objects array and then loop through values and get the names/slugs/term_id etc.
If you're interested in metadata, then you'll have to use get_post_meta function to get meta data using meta keys.
I’m using a headless WordPress with WP-API.
So, I’m exposing yoast data in the API. With something like this:
'yoast_wpseo_title' => wpseo_replace_vars(get_post_meta($post->ID, '_yoast_wpseo_title', true), $post)
I have default SEO titles with snippet variables set for each of my post types under search apperance -> content types.
Odd thing is that if the above default seo title for the post is modified, it seems to save and this function returns me the correct title.
But if the default title is unedited, then the above function returns null. Moreover, if I edit the title back to the default, it also returns null.
I’m not running into this with regular WordPress sites when using standard PHP functions to directly render these fields.
Note: I understand This is plugin-specific. I've tried to get answers from the wordpress forum on Yoast, as well as wordpress stackexchange but to no avail.
I faced a similar situation handling a client's site.
This plugin solved my problem.
https://github.com/niels-garve/yoast-to-rest-api
This exposes the main three attributes that I wanted, into to the api, automatically.
I use the below function to get posts by category after the above plugin, and the content from Yoast is automatically inserted in the response.
function get_category_posts($request) {
$args = array(
'category_name' => $request['category_name'],
'posts_per_page' => $request->get_param( 'per_page' ),
'offset' => ($request->get_param( 'page' )-1),
'orderby' => $request->get_param( 'orderby'),
'order' => $request->get_param( 'order' ),
);
$query = get_posts($args);
if (empty($query)) {
return new WP_Error( 'empty_category', 'there is no post in this category', array('status' => 404) );
}
$formatController = new WP_REST_Posts_Controller('post');
$posts = array();
foreach( $query as $post) {
$data = $formatController->prepare_item_for_response( $post, $request );
$posts[] = $formatController->prepare_response_for_collection( $data );
}
return rest_ensure_response($posts);
}
I am working on this WordPress demo plugin where I want to display/show custom fields for each of these 3 post types (Post, Page, Custom Post Types). No matter how many of them there are.
Let me kind of illustrate the process further as much as I can.
Post Post Type:
1.1 All the Custom Fields of the posts
Page Post Type:
2.1 All the Custom Fields of the pages
Custom Post Type:
3.1 All the Customs Fields of the Custom Post Types individually (slug)
I am searching for built-in or Customized solution.
Thank you! Any direction is highly appreciated.
Finally figured it out with little directions.
Here is how i achieved it.
global $namespace_get_options; // replace with your assigned get_options variable.
// Get all post types
$post_args = array(
'public' => true, // only get publicly accessible post types
'_builtin' => false, // remove builtin post types
);
// generate post type list
$post_types_for_rest = get_post_types($post_args, 'names');
// add built-in 'post and page' post type
$post_types_for_rest['post'] = 'post';
$post_types_for_rest['page'] = 'page';
foreach ($post_types_for_rest as $post_type_for_rest) {
$args = array(
'post_type' => $post_type_for_rest,
'posts_per_page' => -1,
);
$the_query = new WP_Query($args);
$posts = $the_query->posts;
foreach ($posts as $post) {
$post_id = $post->ID;
$custom_field_keys = get_post_custom_keys($post_id);
I am using Wordpress auto suggests using this snippet of code
and currently it is searching all tags, I want it to search only post titles. Any help is appreciated.
This is sql query calling all the tags which needs to be modified for all posts.
<?php global $wpdb;
$search_tags = $wpdb->get_results("SELECT name from wp_terms WHERE name LIKE '$search%'");
foreach ($search_tags as $mytag)
{
echo $mytag->name. " ";
}
?>
These days i had to do some request in a wordpress theme.
In your case ( getting title can be done easier than getting tags, as in your example link ) the stuff can be done easier (i guess).
Firstly you have to make a php page to get posts. As you maybe know you won't be able to use wp stuff in standalone php files, so your file ( let call it get_posts.php ) will look like
<?php
// Include the file above for being able to use php stuff
// In my case this file was in a folder inside my theme ( my_theme/custom_stuff/get_posts.php ).
// According to this file position you can modify below path to achieve wp-blog-header.php from wp root folder
include( '../../../../wp-blog-header.php' );
// Get all published posts.
$list_posts = get_posts( array( 'numberposts' => -1 ) );
// Get "q" parameter from plugin
$typing = strtolower( $_GET["q"] );
//Save all titles
$list_titles = array();
foreach( $list_posts as $post ) { $list_titles[] = $post->post_title; }
// To see more about this part check search.php from example
foreach( $list_titles as $title ) {
if( strpos( strtolower( $title ), $typing ) ){
echo $title;
}
}
?>
I added some comments trying to help you better.
Now stuff get easy, you only have to call your page through jQuery plugin like
$('#yourInput').autocomplete( "path_to/get_posts.php" );
You can directly use wordpress in-build feature to get all post titles
// The Query
query_posts( 'posts_per_page=-1' );
// The Loop
while ( have_posts() ) : the_post();
echo '<li>';
the_title();
echo '</li>';
endwhile;
None of the answers here answer your real question:
How to query JUST post titles
The "raw SQL" way:
Few important things:
escape search for SQL! (also do that for the tags search!) use $GLOBALS['wpdb']->esc_like()
if you only need 1 column, you can use $GLOBALS['wpdb']->get_col()$GLOBALS['wpdb']->get_results() is if you want to fetch more columns in one row
use $GLOBALS['wpdb']->tableBaseName to make your code portable - takes care of the prefixe.g. $GLOBALS['wpdb']->posts
When querying posts you must also think about which post_type and post_status you want to query=> usually the post_status you want ispublish, but post_type may vary based on what you want
WordPress table "posts" contains ALL post types - post, page, custom, but also navigation, contact forms etc. could be there! => I strongly advice to use explicit post_type condition(s) in WHERE ! :)
...$GLOBALS is same as globalizing variabl -today performance difference is little
<?php
// to get ALL published post titles of ALL post types (posts, pages, custom post types, ...
$search_post_titles = $GLOBALS['wpdb']->get_col(
"SELECT post_title from {$GLOBALS['wpdb']->posts}
WHERE (
(post_status = 'publish')
AND
(post_title LIKE '{$GLOBALS['wpdb']->esc_like($search)}%')
)
ORDER BY post_title ASC
"); // I also added ordering by title (ascending)
// to only get post titles of Posts(Blog)
// you would add this to conditions inside the WHERE()
// AND (post_type = 'post')
// for Posts&Pages
// AND ((post_type = 'post') OR (post_type = 'page'))
// test output:
foreach ($search_post_titles as $my_title) {
echo $my_title . " ";
}
?>
The WP_Query way
This is more wordpress but has a little overhead, because although there is a fields param for new WP_Query()/get_posts(), it only has options:
'all' - all fields (also default), 'ids' - just ids, 'id=>parent' - ... if you pass anything else, you still get all, so you still need to add "all" BUT - WP however has filters for altering fields in SELECT.
I tried to make it the same as the raw SQL version, but it depends on how does WP does it's "search" - which I think is %search% for 1 word + some more logic if there are more words. You could leverage the $clauses filter used for fields to also add your custom where INSTEAD of adding the 's' into $args (remember to append to not-lose existing WHEREs $clauses['where' .= "AND ...;). Also post_type => 'any' does not produce always the same results as the raw query in cases like Navigation, Contact forms etc...
Also WP_Query sanitizes the input variables so actually don't escape $args!
<?php
$args = [
'fields' => 'all', // must give all here and filter SELECT(fields) clause later!
'posts_per_page' => -1, // -1 == get all
'post_status' => 'publish',
's' => $search,
// I also added ordering by title (ascending):
'orderby' => 'title',
'order' => 'ASC',
'post_type' => 'any', // all "normal" post types
// 'post_type' => 'post', // only "blog" Posts
// 'post_type' => ['post', 'page'], // only blog Posts & Pages
];
$onlyTitlesFilter = function($clauses, $query) {
// "fields" overrides the column list after "SELECT" in query
$clauses['fields'] = "{$GLOBALS['wpdb']->posts}.post_title";
return $clauses; // !FILTER! MUST RETURN!
};
$onlyTitlesFilterPriority = 999;
// add filter only for this query
add_filter('posts_clauses', $onlyTitlesFilter, $onlyTitlesFilterPriority, 2);
// Pro-tip: don't use variable names like $post, $posts - they conflict with WP globals!
$my_posts = (new WP_Query($args))->get_posts();
// !IMPORTANT!
// !remove the filter right after so we don't affect other queries!
remove_filter('posts_clauses', $onlyTitlesFilter, $onlyTitlesFilterPriority);
// test output:
// note that I used "my"_post NOT just $post (that's a global!)
foreach($my_posts as $my_post) {
echo $my_post->post_title . " ";
}
?>
Don't be confused - you will still get the array of WP_Posts - WP will throw some default properties&values into it, but in reality it will only query and fill-in with real values the fields you specify in the filter.
PS: I've tested these - they are working codes (at least on WP 5.4 and PHP7 :) )
In the website every product is a post, but when we add new products we want something like a newsletter, mostly like a post so in the sidebar of the home page you can see the new products or events of the month.
I'm using pages because I don't want to re-post a product on every new newsletter so I junt wanna display the posts inside the page.
In the products page I separate every product by category and sub-category but since I want to group specific post to publish them on the sidebar I think that pages was the best way to do it.
Right now I'm using this code:
<?php
$productos = new WP_Query(array(
'post__in'=> array(81, 83),
'orderby'=>'title',
'order'=>'ASC'
)
); if ($productos->have_posts()) : while ($productos->have_posts()) : $productos->the_post();
?>
It display the posts with the id of 81 and 83, I would like to show post by slug using 'name' as the codex says because is going to take some time to be checking the ids of the new post, instead of using the name of every new product but It doesn't work in array or I'm doing something wrong.
Now I will love to make something like this work
$names = get_post_meta($post->ID, "names", $single = true);
$productos = new WP_Query(array(
'name'=> array($names),
'orderby'=>'title',
'order'=>'ASC'
)
);
So every time I publish a new page I just write the slugs of the posts that I want to include in the page in a custom field, as you can see I'm not very good with php but I trying to learn and I search a lot for something that could work before asking in here.
I try the ggis inline post plugin and although it works I need the id for every post I want to include and I will need to edit the plugin because I want a different order in the output of the post thats why I don't like to depend to much on plugins.
Update:
So I'm now looking if I can make this using shortcodes, right now I have this:
function producto_func($atts) {
extract(shortcode_atts(array(
'nombre' => ''
), $atts));
global $post;
$pieza = get_page_by_title($nombre,OBJECT, 'post');
echo '<h1>'. $pieza->ID . '</h1>';
}
add_shortcode('producto', 'producto_func');
enter code here
So I just enter the shortcode [producto nombre="ff 244"] in the page and it show its ID, and I can add any number of shortcodes depending on the number of post I need.
But how can I show the entire content of the post.
Any idea?
I find I solution using Shortcodes.
So I put this on my functions.php page
function productos($atts, $content = null) {
extract(shortcode_atts(array(
"slug" => '',
"query" => ''
), $atts));
global $wp_query,$post;
$temp = $wp_query;
$wp_query= null;
$wp_query = new WP_Query(array(
'name'=> $slug,
));
if(!empty($slug)){
$query .= '&name='.$slug;
}
if(!empty($query)){
$query .= $query;
}
$wp_query->query($query);
ob_start();
?>
<?php while ($wp_query->have_posts()) : $wp_query->the_post(); ?>
<h1><?php the_title(); ?></h1>
<div><?php the_content() ?></div>
<?php endwhile; ?>
<?php $wp_query = null; $wp_query = $temp;
$content = ob_get_contents();
ob_end_clean();
return $content;
}
add_shortcode("producto", "productos");
And in my page template I just write [producto slug="MY-SLUG"] and that way I can display multiple post just with the slugs. Hope someone find this useful.
From the Wordpress Codex:
Display post by slug:
$query = new WP_Query( 'name=about-my-life' );
Display page by slug:
$query = new WP_Query( 'pagename=contact' );
UPDATE
Try changing this:
'name'=> array($names),
To this:
'name'=> $names,
The 'name' - and 'pagename' - parameter does not take in an array. Only a string. A comma delimited list SHOULD give you what you need from within your Custom Fields titled "names", though I haven't tested this approach.
Also, thank you for using WP_Query instead of query_posts.