Is it possible to return a list of posts based from the Wordpress Rest API v2 based on their schema:
For List of Schemas:
http://v2.wp-api.org/reference/posts/
I want to filter by sticky field, but the same would go for the rest of the fields.
So far I have:
/wp-json/wp/v2/posts?filter[sticky]=true
/wp-json/wp/v2/posts?filter[sticky]=1
Both return the same response as the standard endpoint:
/wp-json/wp/v2/posts
I have read other material such detailing how to sort by meta or custom taxonomies but I don't believe that's the same as this.
After going through the documentation and looking and posting issues on the WP-API Github repo, it's become clear that the filter[ignore_sticky_posts] should toggle the expected sorting behaviour, so that sticky posts are either always first (default) or ignored (by using filter[ignore_sticky_posts]=true).
However, there's currently a bug in WP API that makes the filter[ignore_sticky_posts] flag unusable.
The best way to fix it now would be to create you own custom endpoint to get the data or IDs of all the sticky posts in your database. By looking at the code discussed in this thread and in the WP-API documentation, I think adding the following code to your functions.php should do the trick:
// Sticky posts in REST - https://github.com/WP-API/WP-API/issues/2210
function get_sticky_posts() {
$posts = get_posts(
array(
'post__in' => get_option('sticky_posts')
)
);
if (empty($posts)) {
return null;
}
return $posts;
}
add_action( 'rest_api_init', function () {
register_rest_route( 'THEME_NAME/v1', '/sticky', array(
'methods' => 'GET',
'callback' => 'get_sticky_posts',
));
});
If you GET /wp-json/THEME_NAME/v1/sticky, you should get an array of all your sticky posts.
I hope this helps.
In addition to Laust Deleuran's answer (thanks Laust!), i've created an altered version of his script which allows you to use the embedded feature of the REST-api.
Although this might not be 'the cleanest' solution, it does allow you to fully use the wp-json's functionality.
function get_sticky_posts(WP_REST_Request $request) {
$request['filter'] = [
'post__in' => get_option('sticky_posts')
];
$response = new WP_REST_Posts_Controller('post');
$posts = $response->get_items($request);
return $posts;
}
add_action( 'rest_api_init', function () {
register_rest_route( 'THEME_NAME/v1', '/sticky', array(
'methods' => 'GET',
'callback' => 'get_sticky_posts',
));
});
This will output the sticky posts in the same schema as a normal /wp-json/wp/v2/posts query would respond.
Related
I have a number of posts in the table wp_3_posts with the post_type "people". This post_type is created using the Admin Columns plugin.
How do I retrieve these?
The documentation for Posts offers filtering by categories or tags but post_type is neither of these.
https://developer.wordpress.org/rest-api/reference/posts/
Thank you :]
If I got your question the right way, you want to get posts of a custom post type with REST API.
You have to set show_in_rest and public in the arguments when you create the custom post type in wordpress.
add_action( 'init', 'my_cpt' );
function my_cpt() {
$args = array(
'public' => true,
'show_in_rest' => true,
'label' => 'My Custom Post'
);
register_post_type( 'mycustompost', $args );
}
More about this: https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-rest-api-support-for-custom-content-types/
With that having set, you can get the posts of post type with using the right parameters in the url.
So if you just want to get posts, you can use:
https://yoursite.com/wp-json/wp/v2/mycustompost?per_page=10
I would suggest setting the per_page to have control if you are getting a lot of posts.
You can also have access to more data without additional HTTP requests using _embed
https://yoursite.com/wp-json/wp/v2/mycustompost?per_page=10&_embed=wp:term,wp:featuredmedia
For example, with this you get taxonomy terms and urls of different featured image sizes.
So you do not need to get all posts (and post types) of your website and then filter by post type, but just get posts of this post type instead. You can than do more filtering using global parameters:
https://developer.wordpress.org/rest-api/using-the-rest-api/global-parameters/
With VueJS (in my opinion better performance) this would look something like:
fetch("https://yoursite.com/wp-json/wp/v2/mycustompost?per_page=10")
.then(response => response.json())
.then((data => {
this.mycustompost = data;
}))
Or if using standard javascript something like:
let state = {
posts: [],
baseUrl: 'https://yoursite.com/wp-json/wp/v2/mycustompost',
perPage: '?per_page=10',
wpFetchHeaders: {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Expose-Headers': 'x-wp-total'
}
}
}
I am trying to create efficient JSON Response controllers for AJAX. So far, instead of passing whole entity to JsonResponse I am creating arrays with necessary data inside where I can easily manage output data leaving less work for JavaScript. My action looks something like this:
public function getOffersAction(Request $request)
{
if (!$request->isXmlHttpRequest()) {
return new JsonResponse(array('message' => 'You can access this only using Ajax!'), 400);
}
/** #var OfferRepository $offerRepository */
$offerRepository = $this->getDoctrine()->getRepository('IndexBundle:Offer');
$offers = $offerRepository->findBy(array('state' => 'available'));
$offersArray = array();
/** #var Offer $offer */
foreach ($offers as $offer) {
$areasArray = array();
foreach ($offer->getAreas() as $area) {
$areasArray[] = array(
'name' => $area->getName()
);
}
$offersArray[] = array(
'id' => $offer->getId(),
'code' => $offer->getCode(),
'title' => $offer->getTitle(),
'city' => $offer->getCity(),
'country' => $offer->getCountry()->getName(),
'latitude' => $offer->getLatitude(),
'longitude' => $offer->getLongitude(),
'areas' => $areasArray
);
}
return new JsonResponse($offersArray, 200);
}
It is all good, ajax is working fast.
At this point I started googling searching if this is a right approach to it. I found out about JMSSerializerBundle which serializes entities. I tried using it, but I am facing problems serializing relationships and how to access related entities data using JS. It is so complicated leaving so many proccessing to do for JS that I start doubting that it is a good approach.
What do you think? What is your experience with it? Which approach is better and why?
I prefer the symfony normalizer/serializer approach.
http://symfony.com/doc/current/components/serializer.html
As described, you can overide serializer to serialize your object in the same custom way for your whole application
In my database there is a content table and when fetching data from this table I would like to append field url to the results, which is based on slug field which is contained in the table. Anyway, I have seen a way to do this in the previous versions of cakephp using behavior for the model of this table and then modifying results in afterFind callback in the behavior class. But in version 3 there is no afterFind callback, and they recommend using mapReduce() method instead in the manual, but this method is poorly explained in the manual and I cant figure out how to achieve this using mapReduce().
After little bit of research I realized that the best way to append the url field field to find results is using formatResults method, So this is what I did in my finders:
$query->formatResults(function (\Cake\Datasource\ResultSetInterface $results) {
return $results->map(function ($row) {
$row['url'] = array(
'controller' => 'content',
'action' => 'view',
$row['slug'],
$row['content_type']['alias']
);
return $row;
});
});
I've been searching for a possibility to copy my Ghost Blog posts to Wordpress.
So far, I've managed to export all ghost data to a JSON file -- do you know any existing tool to convert it to something Wordpress can import?
If not, and I have to build something myself, would you recommend parsing the JSON to a WXR file or similar, or rather import into Wordpress' DB directly?
Thanks in advance!
K.
I migrated a Ghost blog to Wordpress by reading in the Ghost JSON export, massaging it a little and using wp_insert_post to import the posts.
This code should be placed in your theme's functions.php file - you can export your Ghost posts (GhostData.json) at http://example.com/ghost/debug/.
Note: example below doesn't import all data, but most key fields.
/**
* A function used to programmatically create a post in WordPress.
*
* http://tommcfarlin.com/programmatically-create-a-post-in-wordpress/
*
* #returns post ID if successful
* -1 if the post was never created
* -2 if a post with the same title exists
*/
function create_wp_post ($post_details) {
// Initialize the page ID to -1. This indicates no action has been taken.
$post_id = -1;
$post = get_page_by_title($post_details['title'], 'OBJECT', 'post');
// If the page title doesn't already exist, then insert the post
if (is_null($post)) {
// Set the post ID so that we know the post was created successfully
$post_id = wp_insert_post(
array(
'comment_status' => 'closed',
'ping_status' => 'closed',
'post_author' => $post_details['author'],
'post_content' => $post_details['content'],
'post_date' => $post_details['date'],
'post_date_gmt' => $post_details['date_gmt'],
'post_name' => $post_details['slug'],
'post_status' => $post_details['status'],
'post_title' => $post_details['title'],
'post_type' => 'post',
'tags_input' => $post_details['tags_input']
)
);
// Page title already exists, return error
} else {
$post_id = -2;
}
}
/**
* A function used to filter Ghost blog posts into Wordpress format.
*/
function filter_ghost_posts () {
$posts = json_decode(file_get_contents('GhostData.json'), true);
if ($posts) {
foreach ($posts['data']['posts'] as $post) {
$post_details = array(
'author' => $post['author_id'],
'date' => date('Y-m-d H:i:s', $post['published_at'] / 1000),
'date_gmt' => gmdate('Y-m-d H:i:s', $post['published_at'] / 1000),
'id' => $post['id'],
'content' => $post['html'],
'status' => $post['status'],
'slug' => $post['slug'],
'title' => $post['title']
);
// Status
// Fix discrepancy in naming between Ghost and Wordpress
if ($post_details['status'] === 'published') {
$post_details['status'] = 'publish';
}
// Tags
$post_tags_list = [];
foreach ($posts['data']['posts_tags'] as $post_tags) {
if ($post['id'] === $post_tags['post_id']) {
$post_tags_id = $post_tags['tag_id'];
array_push($post_tags_list, $posts['data']['tags'][$post_tags_id]['name']);
}
}
if (count($post_tags_list) > 0) {
$post_details['tags_input'] = implode(',', $post_tags_list);
}
$post_id = create_wp_post($post_details);
if ($post_id == -1 || $post_id == -2) {
// Error handling here
}
}
}
}
add_filter('after_setup_theme', 'filter_ghost_posts');
My recommendation would be to use Google Refine to import the JSON, and export a CSV, then use WP Ultimate CSV Importer Plugin to import it into your WordPress site. Hope this helps.
The question is quite old, but as of 2017 I still wasn't able to find a solution for Ghost > WP posts migration. What I did is:
Export JSON data, as described here - https://help.ghost.org/hc/en-us/articles/224112927-Import-Export-Data
Change a few JSON fields, like title, markdown... to post_title and post_content etc. (list of WP post fields is here - https://codex.wordpress.org/Class_Reference/WP_Post), and remove a few unneeded ones, like update_at or amp. What I left with was:
ID
post_title
post_name
post_content
post_status
meta_title
meta_description
post_author
post_date
Remove other JSON fields/structure, so there's only "posts": []
Use JSON to CSV converter, like this one - https://konklone.io/json/ and download CSV result file.
Now, when you have a CSV file, install WordPress CSV Importer plugin - https://wordpress.org/plugins/wp-ultimate-csv-importer/ (or similar)
Upload CSV file to the importer, check if fields are selected correctly.
Enjoy the imported posts on your WP dashboard ;)
Notice:
Ghost does not enable image exporting with other data (as of 31/01/2017).
You may wish to change "post_status" from "publish" to "pending", so posts are not published right away, before you edit them properly ;)
In case anyone is looking for this in future:
You could use the ghost-to-wp npm package. This will convert the JSON file you get as an export from Ghost into a WordPress-ready WXR file that can be directly imported into WordPress:
$ npm i -g ghost-to-wp
$ ghost-to-wp yourghostexport.json
As noted by #lomza there is still no way to nicely export images as part of the Ghost file so you will have to migrate images manually.
Disclosure: I am the author of ghost-to-wp.
I tried various importers and the best solution ended up just importing directly from RSS URL like https://myghostblog.com/rss/ with import-xml-feed plugin.
P.S. Keep pagination in mind. Your RSS link might show only first page of posts by default, and so for importing other pages you'll have to manually add /2/ /3/ to the URL and importing each separately. (At least, that's what I needed to do.)
I am trying to create a JsonModel with an item in the variables 'html' containing the current rendered view. I would like to add this code to an event:
rather than this method: How to render ZF2 view within JSON response? which is in the controller, I would like to automate the process by moving it to an Event
I have the strategy in my module.config.php:
'strategies' => array(
'ViewJsonStrategy',
)
I have set up a setEventManager in the controller:
$events->attach(MvcEvent::EVENT_RENDER, function ($e) use ($controller) {
$controller->setRenderFormat($e);
}, -20);
Is this the best event to attach it to? would the RENDER_EVENT be better?
Now I would like to change the render of the page based on !$this->getRequest()->isXmlHttpRequest(), (commented out for debug)
public function setRenderFormat($e)
{
//if(!$this->getRequest()->isXmlHttpRequest())
//{
$controller = $e->getTarget();
$controllerClass = get_class($controller);
//Get routing info
$controllerArr = explode('\\', $controllerClass);
$currentRoute = array(
'module' => strtolower($controllerArr[0]),
'controller' => strtolower(str_replace("Controller", "", $controllerArr[2])),
'action' => strtolower($controller->getEvent()->getRouteMatch()->getParam('action'))
);
$view_template = implode('/',$currentRoute);
$viewmodel = new \Zend\View\Model\ViewModel();
$viewmodel->setTemplate($view_template);
$htmlOutput = $this->getServiceLocator()->get('viewrenderer')->render($viewmodel, $viewmodel);
$jsonModel = new JsonModel();
$jsonModel->setVariables(array(
'html' => $htmlOutput,
'jsonVar1' => 'jsonVal2',
'jsonArray' => array(1,2,3,4,5,6)
));
return $jsonModel;
//}
}
Strangely, (or not) this code works and produces the $jsonModel, however is doesn't overwite the normal HTML view with the json, but the same code (without the event) in a controller method, overwrites perfectly.
p.s Is there a better method to do the whole concept?
p.p.s how can I obtain the current View Template from within the controller, without resorting to 8 lines of code?
Thanks in advance!
Aborgrove
you are returning the view model from an event I thinks this doesn't have any effect in current viewmanager view model, fetch the current viewmodel from viewmanager and call setTerminal(true). or replace the created jsonmodel using the viewmanager