I want to have a HTTP POST link in my Wordpress website that lets another server to post an xml file every hour into the Wordpress server and I save it.
I created an index.php file in folders that map with the route I want, let say I need example.com/jobs/uploadFile, so I created a php file inside the folders /jobs/uploadFile of the root Wordpress directory.
<?php
if( $_SERVER['REQUEST_METHOD'] !== 'POST' ) {
header($_SERVER["SERVER_PROTOCOL"]." Method Not Allowed", true, 405);
exit;
}
$postData = trim(file_get_contents('php://input'));
$xml = simplexml_load_string($postData);
if($xml === false) {
header($_SERVER["SERVER_PROTOCOL"]." Bad Request", true, 400);
exit;
}
$xml->asXml('jobs.xml');
http_response_code(200);
1- I send a HTTP POST request via postman, but somehow the server or Wordpress changes it a HTTP GET request, so always the first if condition is executed. I'm using Laravel forge server with Nginx.
2- Appreciate any security advice about this approach, CORS...?
Thanks for your help
Since it may help others, I answer my question. I was doing it the wrong way. The better way to do it is by using actions in a custom Wordpress plugin. Just create a custom plugin and use add_action inside it:
add_action( 'rest_api_init', function() {
register_rest_route(
'myapi/v1', 'myUploadURL',
[
'methods' => 'POST',
'callback' => 'my_upload_function',
'permission_callback' => '__return_true',
]
);
});
And then you can get the $_FILES of the POST request in the my_upload_function() and save it on your server.
I am trying to work with the WooCommerce REST API. So far I have installed the official package and created an index.php file with this code in it:
require __DIR__ . '/vendor/autoload.php';
use Automattic\WooCommerce\Client;
use Automattic\WooCommerce\HttpClient\HttpClientException;
$woocommerce = new Client(
'http://me.commerce.loc/', // Your store URL
'ck_9dadcf73d58fec8b0860bced4b0997d7b3b0f93e', // Your consumer key
'cs_e63d694c035444c45355339171c682052b2707eb', // Your consumer secret
[
'wp_api' => true, // Enable the WP REST API integration
'version' => 'wc/v3' // WooCommerce WP REST API version
]
);
print "<pre>";
print_r($woocommerce);
die();
Printing out $woocommerce gives me this object:
Automattic\WooCommerce\Client Object
(
[http] => Automattic\WooCommerce\HttpClient\HttpClient Object
(
[ch:protected] =>
[url:protected] => http://me.commerce.loc/wp-json/wc/v3/
[consumerKey:protected] => ck_9dadcf73d58fec8b0860bced4b0997d7b3b0f93e
[consumerSecret:protected] => cs_e63d694c035444c45355339171c682052b2707eb
[options:protected] => Automattic\WooCommerce\HttpClient\Options Object
(
[options:Automattic\WooCommerce\HttpClient\Options:private] => Array
(
[wp_api] => 1
[version] => wc/v3
)
)
[request:Automattic\WooCommerce\HttpClient\HttpClient:private] =>
[response:Automattic\WooCommerce\HttpClient\HttpClient:private] =>
[responseHeaders:Automattic\WooCommerce\HttpClient\HttpClient:private] =>
)
)
Is it possible to get wooCommerce data through this object? If no then how can I do it?
Thank you very much.
You do not require to add above code or create index.php
just use this end point to get all orders list : https://example.com/wp-json/wc/v3/orders
To get all Products : https://example.com/wp-json/wc/v3/products
This way you can get list of order and products.
To use rest api and do all operations in woocommerce using rest api please refer this link : https://woocommerce.github.io/woocommerce-rest-api-docs/
There are two woocommerce rest api versions which are V2 and V3 you can use any from this.
I'm trying to post a comment to WordPress (4.7.0) using basic authentication as described in the documentation and in WP REST API: Setting Up and Using Basic Authentication.
However, I keep getting 401 errors back.
{"code":"rest_comment_login_required","message":"Sorry, you must be logged in to comment.","data":{"status":401}}
I activated the basic authentication plugin which then should turn this call into an authenticated call, right?
You need to add a filter to your theme's functions.php file:
add_filter( 'rest_allow_anonymous_comments', function ( $allow_anonymous, $request ) {
// ... custom logic here ...
return true; // or false to prohibit anonymous comments via post
}, 10, 2 );
Documentation: https://developer.wordpress.org/reference/hooks/rest_allow_anonymous_comments/
Go to your root WordPress folder like rootfolder/wp-includes/rest-api/endpoints
Open the file: class-wp-rest-comments-controller.php
Change the line:
$allow_anonymous = apply_filters( 'rest_allow_anonymous_comments', false , $request );
to
$allow_anonymous = apply_filters( 'rest_allow_anonymous_comments', true, $request );
That's all
I am considering to improve security of my Wordpress website, and in doing so have come across WP REST API being enabled by default (since WP 4.4 if I'm not mistaken).
What is a safe way to disable it?
By "safe" here I mean that it does not cause unexpected side-effects, e.g. does not break any other WP core functionality.
One possible approach would be to use .htaccess rewrite rules, but surprisingly I haven't found any 'official' instructions on doing so.
Any help or recommendation is greatly appreciated :)
Update:
3rd-party plugins is not the solution I am looking for. Although I'm aware there are plenty of them that solve the task, they include many extra features that slow down the website. I would hope there is a one-line solution to this problem without the overhead of an extra plugin.
Update 2:
Here is the official opinion of Wordpress: https://developer.wordpress.org/rest-api/using-the-rest-api/frequently-asked-questions/#can-i-disable-the-rest-api
According to this, the Wordpress team wants future WP functionality to depend on the new REST API. This means there is no guaranteed safe way to disable the REST API.
Let's just hope there are enough security experts taking care of WP security.
Update 3:
A workaround is presented in WordPress API Handbook - you can Require Authentication for All Reque​sts
This makes sure that anonymous access to your website's REST API is disabled, only authenticated requests will work.
From the author original question I've chosen option 2 that came from wordpress official recommendations(https://developer.wordpress.org/rest-api/using-the-rest-api/frequently-asked-questions/#can-i-disable-the-rest-api). So just put in your functions.php to let only logged in users use the rest api (but just cross check original link in case my code block is outdated ;) ):
UPD(01-10-2021):
add_filter( 'rest_authentication_errors', function( $result ) {
// If a previous authentication check was applied,
// pass that result along without modification.
if ( true === $result || is_wp_error( $result ) ) {
return $result;
}
// No authentication has been performed yet.
// Return an error if user is not logged in.
if ( ! is_user_logged_in() ) {
return new WP_Error(
'rest_not_logged_in',
__( 'You are not currently logged in.' ),
array( 'status' => 401 )
);
}
// Our custom authentication check should have no effect
// on logged-in requests
return $result;
});
You can disable it for requests other than localhost:
function restrict_rest_api_to_localhost() {
$whitelist = [ '127.0.0.1', "::1" ];
if( ! in_array($_SERVER['REMOTE_ADDR'], $whitelist ) ){
die( 'REST API is disabled.' );
}
}
add_action( 'rest_api_init', 'restrict_rest_api_to_localhost', 0 );
The accepted answer disables all API calls from unauthenticated users, but nowadays lot of plugins are dependent on this API's functionality.
Disabling all calls will lead to unexpected site behavior which happened in my case also when I used this code.
For example, ContactForm7 makes use of this API for sending contact info to DB (I think) and for ReCaptcha validation.
I think it would be better to disable some (default) endpoints for unauthenticated users like this:
// Disable some endpoints for unauthenticated users
add_filter( 'rest_endpoints', 'disable_default_endpoints' );
function disable_default_endpoints( $endpoints ) {
$endpoints_to_remove = array(
'/oembed/1.0',
'/wp/v2',
'/wp/v2/media',
'/wp/v2/types',
'/wp/v2/statuses',
'/wp/v2/taxonomies',
'/wp/v2/tags',
'/wp/v2/users',
'/wp/v2/comments',
'/wp/v2/settings',
'/wp/v2/themes',
'/wp/v2/blocks',
'/wp/v2/oembed',
'/wp/v2/posts',
'/wp/v2/pages',
'/wp/v2/block-renderer',
'/wp/v2/search',
'/wp/v2/categories'
);
if ( ! is_user_logged_in() ) {
foreach ( $endpoints_to_remove as $rem_endpoint ) {
// $base_endpoint = "/wp/v2/{$rem_endpoint}";
foreach ( $endpoints as $maybe_endpoint => $object ) {
if ( stripos( $maybe_endpoint, $rem_endpoint ) !== false ) {
unset( $endpoints[ $maybe_endpoint ] );
}
}
}
}
return $endpoints;
}
With this, the only endpoints now open are the ones installed by the plugins.
For complete list of endpoints active on your site, see https://YOURSITE.com/wp-json/
Feel free to edit $endpoints_to_remove array as per your requirement.
If you have custom post type, make sure to add those all to the list too.
In my case, I also changed the default endpoint prefix from wp-json to mybrand-api. This should act a deterrent for bots that were making thousands of brute-force requests.
Here is what I did:
// Custom rest api prefix (Make sure to go to Dashboard > Settings > Permalinks and press Save button to flush/rewrite url cache )
add_filter( 'rest_url_prefix', 'rest_api_url_prefix' );
function rest_api_url_prefix() {
return 'mybrand-api';
}
Disabling REST API was not a bad idea, after all.
It actually opened a huge hole in all websites!
In wordpress 4.4 there was a way
Here, I've found a possible solution with .htaccess but should be carefully tested in combination with whatever else is in your .htaccess file (e.g., pretty-url rules added by wordpress itself):
# WP REST API BLOCK JSON REQUESTS
# Block/Forbid Requests to: /wp-json/wp/
# WP REST API REQUEST METHODS: GET, POST, PUT, PATCH, DELETE
RewriteCond %{REQUEST_METHOD} ^(GET|POST|PUT|PATCH|DELETE) [NC]
RewriteCond %{REQUEST_URI} ^.*wp-json/wp/ [NC]
RewriteRule ^(.*)$ - [F]
A very drastic method, is also to have a 404.html webpage in your root and then add this line:
# WP REST API BLOCK JSON REQUESTS
# Redirect to a 404.html (you may want to add a 404 header!)
RewriteRule ^wp-json.*$ 404.html
Note that, unless you use a static page, i.e., not involved with wordpress functions, if you want to return a 404 error with an appropriate error page, this is a complete separate topic, with a lot of issues when Wordpress is involved
if you want to disable Wordpress REST API completely use this code:
// Disable Wordpress REST API
remove_action( 'init', 'rest_api_init' );
remove_action( 'rest_api_init', 'rest_api_default_filters', 10 );
remove_action( 'rest_api_init', 'register_initial_settings', 10 );
remove_action( 'rest_api_init', 'create_initial_rest_routes', 99 );
remove_action( 'parse_request', 'rest_api_loaded' );
With the plugin "Disable REST API" you can select which APIs you want to enable, e.g. the contact form 7 API. See the plugin's settings (yoursite.com/wp-admin/options-general.php?page=disable_rest_api_settings)
add_filter('rest_enabled', '__return_false');
add_filter('rest_jsonp_enabled', '__return_false');
There are several points you need to "turn off". Also, you might want to place some kind of notice to someone coming to that page...
Here is what I used (and was checked):
function itsme_disable_feed() {
wp_die( __( 'No feed available, please visit the Example!' ) );
}
add_action('do_feed', 'itsme_disable_feed', 1);
add_action('do_feed_rdf', 'itsme_disable_feed', 1);
add_action('do_feed_rss', 'itsme_disable_feed', 1);
add_action('do_feed_rss2', 'itsme_disable_feed', 1);
add_action('do_feed_atom', 'itsme_disable_feed', 1);
add_action('do_feed_rss2_comments', 'itsme_disable_feed', 1);
add_action('do_feed_atom_comments', 'itsme_disable_feed', 1);
As per wp_die() docs:
This function complements the die() PHP function. The difference is
that HTML will be displayed to the user. It is recommended to use this
function only when the execution should not continue any further. It
is not recommended to call this function very often, and try to handle
as many errors as possible silently or more gracefully.
Hope this helps.
I'm trying to hit my Wordpress API using Basic Auth with Guzzle (http tool) from my middleware (Laravel).
$username = 'myAdminUserName';
$password = 'myAdminPassword';
$uri = 'https://example.com/wp-json/mysite-api/cleared-action';
$response = $this->guzzle->put(
$uri,
[
'headers' => [
'Authorization' => 'Basic ' . base64_encode( $username . ':' . $password )
],
'body' => [
'user_id' => $wordpressId //passed into this function
]
]
);
It then hits the route set up in my Wordpress API
$routes['/mysite-api/cleared-action'] = array(
array(array($this, 'automatedClearing'), WP_JSON_Server::ACCEPT_JSON
| WP_JSON_Server::CREATABLE
| WP_JSON_Server::EDITABLE)
);
However that is as far as it gets. It does not hit my automatedClearing endpoint which looks like this
public function automatedClearing() {
global $container;
\Groups_User_Group::create( array('user_id' => 2903, 'group_id' => 13));
$mySiteServices = $container['services'];
$this->$mySiteServices->sendClearedEmail(2903); //2903 = user_id
}
I've used hardcoded values for the users ID.
I keep getting a 200 response from my call, so it definitely hits the route, but does not execute the endpoint. The response is basically just an empty one.
My Wordpress access.log shows the route being hit, but my error.log doesn't show anything. By the way, this is a laravel Homestead (vagrant) box hitting a Wordpress vagrant box.
I'm wondering if this is because the WP-API requires a nonce? But I thought nonce was only needed within Wordpress, whereas this is an external app hitting Wordpress.
I'm pretty stuck on this. Any guidance is greatly appreciated
Try to test it using postman ... if this works via postman then you have the problem with laravel or guzzle