Wordpress REST API - Post Request for YOAST fields - python

I'm using python to create wordpress post taking care also of the YOAST fields, using the wordpress rest api. On YOAST website I found this statement:
The Yoast REST API is currently read-only, and doesn't currently
support POST or PUT calls to update the data.
At the same time, I'm wondering if there is some workaround to be able to update the Yoast fields by post request, something like this (that off-course is not working right know):
post = {
'title' : 'My title',
'content' : 'This is my first post created using rest API Updated',
'yoast_head_json': {'title': 'This field should be UPDATED by POST REQUEST'},
}
I found a code snippet at this link, that maybe would be a useful starting point and I report it below:
class YoastUpdateController extends WP_REST_Controller {
public function register_routes() {
register_rest_route( 'wp/v2/', '/action/', array(
'methods' => 'GET',
'callback' => [$this, 'update_yoast_meta']
));
}
function update_yoast_meta($data) {
$postID = $_GET['postID'];
$metadesc = $_GET['metaDesc'];
if ($postID && $metadesc) {
$this->add_to_yoast_seo($postID, $metadesc);
}
}
function add_to_yoast_seo($post_id, $metadesc){
$ret = false;
$updated_desc = update_post_meta($post_id, '_yoast_wpseo_metadesc', $metadesc);
if($updated_desc){
$ret = true;
}
return $ret;
}
}
function register_yoast_update_controller() {
$controller = new YoastUpdateController();
$controller->register_routes();
}
add_action( 'rest_api_init', 'register_yoast_update_controller' );
I placed the above code in function.php, I hope it is the right place.
How could I update all/some of the fields of YOAST by rest api post request? Below some fields (E.g. title, description...)
"yoast_head_json": {
"title": "Post 1 - MyWebsite",
"description": "Meta description added in backend",
"robots": {
"index": "index",
"follow": "follow",
"max-snippet": "max-snippet:-1",
"max-image-preview": "max-image-preview:large",
"max-video-preview": "max-video-preview:-1"
},
Thank you all,

According to yoast documentation: The Yoast REST API is currently read-only, and doesn't currently support POST or PUT calls to update the data.
https://developer.yoast.com/customization/apis/rest-api/#can-i-use-this-api-to-update-data

Related

Concurrent request in django

Concurrent request to Django API from vue returns the response from the last request for both.
Here is my snippet from vue component
methods:{
users(){
axios.get('users').then((response) => {
this.sers = response.data;
}).catch((error) => {
console.log(error);
});
},
new_users(){
axios.get('users', {
params: {type:'new'},
}).then((response) => {
this.new_users = response.data;
}).catch((error) => {
console.log(error);
});
}
},
mounted(){
this.users();
this.new_users();
}
and my python snippet from the Django view
def list_objects(request):
if 'type' in request.GET and request.GET['type'] =='new' :
#return new users
else:
#return users
The problem is the new_users() and users() methods respond with new users data(the one which called last, if we call the users() method last both methods get users data )
The problem is with the Django development server. When I switch to gunicorn all problems gone and now working as expected.

Getting stuck in view when using Ajax with Django

I'm trying to use Ajax in order to validate if a value of a field already exists in the DB.
urls.py:
#App Auxiliares_Tipos:
path('ajax/validar_tipaux/', validar_tipaux),
path('Tipos_de_auxiliares/', tipoAuxi),
views.py:
def validar_tipaux(request):
codigo = request.GET.get('codigo', None)
print(codigo)
data = {
'is_taken': TipoAux.objects.filter(codigo__iexact=codigo).exists()
}
return JsonResponse(data)
validation.js is included in my html body.
validation.js:
$("#id_codigo").change(function () {
var tipaux = $(this).val();
console.log(tipaux);
$.ajax({
url: '/ajax/validar_tipaux/',
data: {
'tipaux': tipaux
},
dataType: 'json',
success: function (data) {
if (data.is_taken) {
console.log('Existe');
alert("That value is already taken.");
}
}
});
});
id_codigo is the id of the field that I'm checking if exists with Ajax.
The error: it works almost at all, the JavaScript detects changes on id_codigo properly (I'm trying to check everything with print/console.log). But it gets stuck in the view validar_tipaux where it prints None as codigo's value.
What's wrong?
You're sending the data as tipaux but your view is looking for codigo.

How to return actions and parameters in OPTIONS request with django rest framework

I try to return a list of select options for countries using django-countries and django rest framework. I use JWT_AUTH for the authentication.
When I try a options request:
curl \
-H "Authentication: JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFsYmVydG9fdmVudGEiLCJ1c2VyX2lkIjoyLCJlbWFpbCI6IiIsImV4cCI6MTUwODE2Mzg4Mn0.svxqTThCahSl1Vu27sMjuJyd1PRLk28-Xgn2OKKb5-g"\
-X OPTIONS \
-v http://127.0.0.1:8000/api/v1/core/perfilViajeroUserPass/
The response is:
{
"name":"Perfil Viajero User Pass Create",
"description":"",
"renders":["application/json","text/html"],
"parses":[
"application/json",
"application/x-www-form-urlencoded",
"multipart/form-data"
]
}
But I think that it should be something like this by default:
{
"name": "To Do List",
"description": "List existing 'To Do' items, or create a new item.",
"renders": [
"application/json",
"text/html"
],
"parses": [
"application/json",
"application/x-www-form-urlencoded",
"multipart/form-data"
],
"actions": {
"POST": {
"note": {
"type": "string",
"required": false,
"read_only": false,
"label": "title",
"max_length": 100
}
}
}
}
Someone could help me? thanks.
If you want to change some of the content:
name is the view's get_view_name which is the view's name slightly reworked.
description is the view's get_view_description which reworks the view's docstring.
Otherwise if you want something more complex, you'll probably want to customize the view's metadata as explained in http://www.django-rest-framework.org/api-guide/metadata/#custom-metadata-classes
I have found the solution.
I change my view class type from APIView to generics.CreateAPIView and know it works. Thank you very much.
Adding another answer since I recently ran into the same issue and found it a bit mystifying -- when making an OPTIONS request, Django Rest Framework uses the view's Metadata class to construct a response. The default Metadata class is SimpleMetadata, as mentioned in the docs. However, SimpleMetadata only adds the actions key to the response body if the view in question defines the method get_serializer(). I'm not sure why this is the case, but see here for the relevant code.
rest_framework.generics.GenericAPIView defines a get_serializer() method, so (authenticated) OPTIONS requests made to these views will return a response body with the actions key. But rest_framework.views.APIView does not define this method, so the actions key will always be absent.
If you have to use rest_framework.views.APIView, you could work around this by defining a get_serializer() method on your APIView class. Which feels a little hacky, but I tested it and it works:
class MyView(views.APIView):
def get_serializer(self):
return MySerializer()
def post(self):
...

Sailsjs route and template rendering

This question is directed to anyone with both flask (python) and sailsjs knowledge. I am very new to the concept of web frameworks and such. I started using flask but now I must use Sailsjs. In flask, I can define a route as:
#app.route('/company/<org_name>')
def myfunction(org_name):
...use org_name to filter my database and get data for that company...
return render_template('companies.html', org_name=org_name, mydata=mydata)
Where I can use myfunction() to render a template in which I can pass the parameters org_name and mydata.
In sails, I am confused as to how to define my route with a given parameter. I understand:
'/': {
view: 'companies'
}
but I am not sure how to make the route dynamic in order to accept any variable org_name.
Another problem is that in python, mydata is a query from a MySQL database. I have the same data base connected to Sailsjs with the model completely set up but I am sure this model is useless. The site that I am creating will not be producing any new data (i.e. I will neither be updating nor saving new data to the database).
My Question is thus: with
'/company/:org_name': {
view: 'companies'
}
where should I create the function that filters the database? how should I be sure that sails will pass that org_name parameter into the function and how should I pass the data as a parameter into an html template?
Thanks a ton.
There are 2 options here but it helps to explain a bit about each in order for you to pick the best course of action.
Firstly, routes...You can indeed as you have shown render a view from a route directly, but you can also do a few other things. Below are 2 snippets from the sails.js website docs:
module.exports.routes = {
'get /signup': { view: 'conversion/signup' },
'post /signup': 'AuthController.processSignup',
'get /login': { view: 'portal/login' },
'post /login': 'AuthController.processLogin',
'/logout': 'AuthController.logout',
'get /me': 'UserController.profile'
}
'get /privacy': {
view: 'users/privacy',
locals: {
layout: 'users'
}
},
Snippet 1 shows how you can render a view directly as you have shown but also how you can point to a controller in order to do some more complex logic.
The login within your controller could mean that for the /me "GET" route you can execute a database query within the "profile" method to accept a get parameter, find a user and then display a view with the users data within. An example of that would be:
Profile: function (req,res){
User.find({name: req.param('name')}.exec(function founduser(err,result){
return view('profile',{userdata: result});
});
}
In the second snipped from the sails docs you can see "locals" being mentioned. Here in the GET privacy route we see that the view is being told whether to use the layout template or not. However, with that being said there is nothing stopping you pushing more into the locals such as users name etc.
In my opinion and what I feel is best practice, I would leave your routes.js to be quite thin and logicless, put the database queries/logic/redirections in to your controller.
For your specific example:
My routes.js file may look like this
// config/routes.js
module.exports.routes = {
'get /companies': 'CompanyController.index',
'get /companies/:orgname': 'CompanyController.company'
}
This allows the first route to potentially show a list of companies by going to /companies and my second route may fire when a get request is made based on clicking a company name e.g. /companies/Siemens
My CompanyController.js for these may look like this:
module.exports = {
index: function (req, res) {
return res.view('companieslist');
},
company: function (req, res) {
var companyName = req.param('orgname'); //Get the company name supplied
//My company model which could be in api/models as Company.js is used to find the company
Company.find({name: companyName}).limit(1).exec(function companyresult(err,result){
//Error catch
if(err){return res.negotiate(err)};
//The result of our query is pushed into the view as a local
return res.view('company',{companydata: result}); //Within the .find callback to ensure we keep async
});
}
};
In my view I can access the data retrieved under "companydata" e.g. for EJS:
<%=companydata[0].name%>
If you need any further help/clarifications let me know. I do recommend taking a look at the sails.js documentation but if you really want to get your head around things I recommend sails.js in Action which is an ebook from mannings. A couple of days of reading really got me up to speed!

Django + Angular2: How to fetch data from database?

I am using angular2 as a front end in my html pages.I have a django project that uses postgresql.
Which is the best approach to use the angular2 in the django project to connect to the django models and the database to perform basic operations(CRUD)like Read,Update etc?
Currently I need to fetch the data from the database dynamically.
(e.g.If user clicks on the product from the product list then product details should be retrieved from the database and it is shown to the user)
Any advice or reference example link will be helpful.
Create REST api end points using Django (use DRF for standard REST api's or just use vanilla django to generate json response for the requests and call it REST api).
For ex:
/product/:id is the api end point you've created to fetch the details of a particular product in Django
Then use Angular to request throught those API's and get the responses and do whatever you want with that data.
For ex:
make a get request to /product/1 to fetch the details of a product with PK = 1 when the user clicks that product.
Browse through Github for some inspiration.
Checkout django-rest-framework
DRF is a django app that makes building ReST apps a breeze.
Checkout their quick tutorial to get a sense of how to use DRF in your project.
I'm recently working on the similar project you have. My approach is just like #praba230890 mentioned above.
Here are some samples...
Django
In views.py
class HView(APIView):
def get(self, request, format=None):
request_hero_id = request.query_params.get('id', None)
if request_hero_id:
return Response(
{
'id': 1,
'name': 'test',
'position': 'mid'
},
status=status.HTTP_200_OK
)
return Response(
{ 'error': 'does not exist' },
status=status.HTTP_404_NOT_FOUND
)
class HsView(APIView):
def get(self, request, format=None):
return Response(
[
{
'id': 1,
'name': 'test',
'position': 'mid'
},
{
'id': 2,
'name': 'test',
'position': 'mid'
}
],
status=status.HTTP_200_OK
)
In urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'', include('shweb.urls')),
]
You will need to install django-cros-headers if you run into CROS errors. Also, you will need to configure your settings.py
Angular2
In api-service.service.ts
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/toPromise';
import { Hero } from '../utils/hero';
#Injectable()
export class ApiService {
/** Modify this later */
private backend_api_url: string = 'http://localhost:8000/api/';
private api_headers: Headers = new Headers(
{ 'Content-Type': 'application/json' }
);
constructor(private http: Http) { }
getHero(id: number): Promise<Hero>{
const url = `${this.backend_api_url}htest/?id=${id}`;
return this.http.get(url).toPromise().then(
response => response.json() as Hero
).catch(this.handleError);
} // END getHero
getHeroes(): Promise<Hero[]>{
const url = `${this.backend_api_url}htests`;
console.log(url);
return this.http.get(url).toPromise().then(
response => {
console.log(response.json());
return response.json() as Hero[];
}
).catch(this.handleError);
} // END getHeroes
private handleError(error: any): Promise<any>{
console.error('An error occurred', error); // TODO: update this
return Promise.reject(error.message || error);
}
}
In hero.ts
export class Hero{
id: number;
name: string;
position: string;
}
In your component file, inject the api-service into component
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit{
title: string = 'Dashboard';
heroes: Hero[] = [];
constructor(private apiService: ApiService){}
ngOnInit(): void{
this.getHeroes();
}
getHeroes(): void{
this.apiService.getHeroes().then(heroes => this.heroes = heroes);
} // END getHeroes
}
Basically, using API to retrieve data and cast into class; then, you can use those data.
PS. I haven't touched the credentials and security part. I believe you need to have some sort of Authentication implemented for secure API communication. (In my case, only GETs are allowed. Therefore, I put the security part for later.)
Hope this would help!

Categories

Resources