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);
}
Related
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.
I really hope you can help me here because it's literally driving me crazy and keeping me from sleeping for 3 days now.
I've been looking everywhere to find a solution to my questioning and everytime I think I'm finally getting somewhere the answers are either too old or the links down, or when someone is facing the exact same issue they never get an answer.
SO. Here is the thing.
In my function.php I created a CPT so my users can create posts with WP User Frontend without polluting my blogs. Now, since the posts are in a CPT, they no longer show up in the built-in Posts tab that Buddypress provides. So, I then added a custom tab to display their posts on their profile.
And now it's getting messy.
I managed to get the posts from the CPT, everything works fine (I know it because if I echo the post thumbnail and title I see them). But I can't figure out how to get the freaking Buddypress template to style the posts list. I think I've read something like more than a hundred threads, I went through Wordpress and Buddypress codex, I even dug into my Buddypress plugin files to find the templates and blog loops and try to understand how it works. But still, nothing.
Here is the code I have so far
function bp_costumes_tab_setup_nav() {
global $bp;
$parent_slug = 'profil-costumes';
bp_core_new_nav_item( array(
'name' => 'Costumes tab',
'slug' => $parent_slug,
'parent_url' => $bp->loggedin_user->domain . $parent_slug.'/',
'screen_function' => 'costumes_tab_show_screen',
'position' => 3,
'default_subnav_slug' => 'profil-costumes'
) );
}
add_action( 'bp_setup_nav', 'bp_costumes_tab_setup_nav' );
function costumes_tab_show_screen() {
add_action( 'bp_template_content', 'bptab_costumes_content' );
bp_core_load_template( apply_filters( 'bp_core_template_plugin', 'members/single/plugins' ) );
}
function bptab_costumes_content() {
$myposts = get_posts( array(
'posts_per_page' => -1, // set the number of post to show, -1 if all
'author' => bp_displayed_user_id(),
'post_type' => 'cptgalerie',
'orderby' => 'post_date',
'order' => 'DESC',
'post_status' => 'publish'
));
if( ! empty( $myposts ) ) {
foreach($myposts as $post) {
setup_postdata( $post );
**HERE I WANT THE POSTS FROM CPT TO BE DISPLAYED LIKE IN THE BUILT-IN POSTS TAB**
}
wp_reset_postdata();
} else {
echo '<div class="info" id="message">
<p>Aucun album publié.</p>
</div>';
}
}
As I'm using Elementor Pro I also tried creating a loop and add the shortcode in my php with
echo do_shortcode ("[elementor-template ID='xxx']");
but it gets the template without the post info. It just keeps repeating the user's name (which is technically the "post title" since I used the "post title" widget in my template, I know, but it's not the title I want). Here too I tried to understand how it works by digging into another plugin I use that gets Elementor templates to display posts.
I found other answers where "if ( ! empty...)" is replaced by "if (have posts)... while" but it doesn't seem to work. I've read also that now the "bp_core_load_template" should be replaced by something else... many tests but no results. I also found that it has something to do with some archive template.
I'm lost.
Please, pleeeeeaaaase, can someone help me?
I need to sort it out, get it out of my mind and SLEEP.
Thank you!
I have made my first plugin and it all works on the front end but I am having some weird backend conflict with the gutenberg. I have done two things, made my plugin automatically add the pages / overwrite them when they've checked off, and made the plugin shortcode.
Here is the problem on my gutenberg:
As you can see there are random red diamonds on the page. When I use the inspector I can see it has code from my plugin I created...
Here is how I created my plugin
First inside my functions page I registered a new short code.
add_shortcode('parts_listing_portal', 'portal_parts_list');
function portal_parts_list(){
include "shortcodes/parts_listing_shortcode.php";
return ;
}
Then I made content for inside the shortcode using JS, PHP, and HTML.(this is a big file with includes and API calls)
After the page looked the way I would like, I created a new function to work on my option submit. This function creates the page with the shortcode inside.
//Add parts
if ( get_option( 'parts' ) === "checked") {
$parts_list = array(
'post_title' => 'Parts',
'post_type' => 'page',
'post_name' => 'Parts',
'comment_status' => 'closed',
'ping_status' => 'closed',
'post_content' => '[parts_listing_portal]',
'post_status' => 'publish',
'post_author' => get_user_by( 'id', 1 )->user_id,
'menu_order' => 0
);
// PARTS LIST
if(get_page_by_title('Parts') == null) {
wp_insert_post($parts_list);
}else{
$post_exists = get_page_by_title("Parts" );
$update_post = array('ID' => $post_exists->ID);
$post_update = wp_parse_args($parts_list, $update_post);
wp_update_post($post_update);
}
When my function adds to the page & you go to the gutenberg editor it shows the full page for a split second then goes away. I feel I missed a statement somewhere to only show on "page" but I have no idea where to look. I've spent a lot of time researching it but couldn't find it.
Thank you
Whenever adding a shortcode make sure to check iif in admin area. If in admin area return nothing
function portal_parts_list(){
if ( is_admin()){
return;
}else {
include "shortcodes/parts_listing_shortcode.php";
return ;
}
}
add_shortcode('part_description_portal', 'portal_parts_list');
I'm writing what I thought was a simple series of functions to assign a "deletion date" to media, then auto-delete those expired media when the site is visited.
The post_meta for deletion date is set for the images via an online form when the images are uploaded (using formidable pro forms and the "after_create_entry" hook. I can confirm that the meta field is created successfully, and the deletion date is assigned properly (called 'mtp_deletiondate'. To test, I did a wp_query on a custom page and each image has a properly set deletion date.
Next, I wanted to run a function that checked for expired images (set to be 21 days after date of upload), and if they are expired, to delete them. I want to trigger this function whenever I access the admin, because I figure I get in there at least once a month to run updates, and it's a good time to clean out the old images. For this situation, I decided not to do a cron job since I can reliably visit the site once a month anyway.
The issue is the function doesn't seem to be triggering, and I don't know if it's because the function is broken or because I'm using the wrong action, or both. Some research tells me to use the admin_init, but I've also tried "wp", and "wp-footer". It might be that I'm just misunderstanding the process. My function (in my theme's functions.php):
function drick_delete_expired_uploads() {
// WP_Query arguments
$args = array (
'post_status' => 'any',
'post_type' => array( 'Attachment' ),
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'mtp_deletiondate',
),
),
);
// The Query
$mediaquery = new WP_Query( $args );
// The Loop
if ( $mediaquery->have_posts() ) {
while ( $mediaquery->have_posts() ) {
$mediaquery->the_post();
date_default_timezone_set('America/Denver');
$CurrentDate = date('Y-m-d h:i');
$CurrentDateStr = strtotime($CurrentDate);
$DeletionDate = get_post_meta( $post->ID, 'mtp_deletiondate', true );
$DeletionDateStr = strtotime($DeletionDate);
if ( isset($DeletionDateStr) ) {
if ( $DeletionDateStr < $CurrentDateStr ) {
wp_delete_attachment( $post->ID, true );
}
}
}
} else {
// no posts found
} // IF HAVE POSTS
// Restore original Post Data
wp_reset_postdata();
}
add_action('admin_init', 'drick_delete_expired_uploads');
If I save my functions.php, then reload the Wordpress dashboard, then check my media, the expired images are still there. HOWEVER, if I add this function to an actual page then visit the page, it does work. So I believe the function is doing what it's supposed to, it's just not getting triggered properly? I also added a quick wp_mail() to the function in my functions.php, and when I visited the admin it did trigger the email, so I guess the function is firing.
I would appreciate any insight, thank you!
So I think I figured it out, but I don't know that I have an explanation as to why it works. Essentially it looks like wp_delete_attachment wasn't working, but wp_delete_post DOES work. I've tested and confirmed with three additional images that the function auto delete is triggered when accessing the admin dashboard. I also changed the way the query arguments are structured by only querying the expired images, rather than querying ALL images that have a mtp_deletiondate meta then running a conditional statement within the query. Don't know if that's related or not. The final working function:
function drick_delete_expired_uploads() {
// WP_Query arguments
date_default_timezone_set('America/Denver');
$CurrentDate = date('Y-m-d h:i');
$args = array (
'post_status' => 'any',
'post_type' => array( 'Attachment' ),
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'mtp_deletiondate',
'value' => $CurrentDate,
'compare' => '<',
'type' => 'DATE',
),
),
);
// The Query
$mediaquery = new WP_Query( $args );
// The Loop
if ( $mediaquery->have_posts() ) {
while ( $mediaquery->have_posts() ) {
$mediaquery->the_post();
wp_delete_post(get_the_ID());
}
} else {
// no posts found
} // IF HAVE POSTS
// Restore original Post Data
wp_reset_postdata();
}
add_action('admin_init', 'drick_delete_expired_uploads');
Still look forward to any feedback from someone in the know that can tell me why the previous version wasn't working (looking to learn here). Thanks!
I've got some custom post types set up in Wordpress using Pods and linking them using relationship fields. Now I'd like to display (and link to) the related custom posts 'postB' from a single post 'postA'. I also just want to display those posts which got a date in the future, which is also stored in a custom field in 'postB'.
This is what I've currently got so far, put into a theme template file (single-posta.php):
<?php
$id = get_the_ID();
$params = array(
'where' => 'postB.ID IN ('.$id.')',
'limit' => -1, // Return all
//'oderby' => 'postB.customDate, (order is not working, so I commented it out)
//'order' => 'ASC'
);
$postsB = pods( 'postB', $params );
if ( 0 < $postsB->total() ) {
while ( $postsB->fetch() ) {
?>
<p>
<?php echo $postsB->display( 'title' ); ?><br>
<?php echo $postsB->display( 'customDate' ); ?><br>
</p>
<?php
}
}
?>
So how can I
order the results?
link to these posts?
limit them to dates in the future?
Btw. is this the right way to get those posts anyway?
You could use WP_Query too, but since you're using the Pods find() syntax, I'll give you the correct code for what you're after using that:
$params = array(
'where' => 'postB.ID IN ('.$id.')',
'limit' => -1, // Return all
'orderby' => 'customDate.meta_value ASC'
);
$postsB = pods( 'postB', $params );
Pods doesn't let you create fields with capital letters though, so it's likely you created that one outside of Pods, correct? Just double checking, if it was created with Pods it would be named 'customdate'