I need to run regular updates from external app to wordpress website through REST API. But the performance of the API is awful.
I see around the SHORTINIT method, that loads minimal WP but it doesn't load rest api either.
My question is how can I make a php file that only loads features I need and also respond to all rest api endopoints?
For example if i make a /wm-minimal/index.php how can I make calls to /wp-minimal/wp-json/wp/v2 which is the url part that wordpress api responds?
I've never tried this but it's possible that if you minimal includes the red files you could run do_action('rest_api_init')
This is a big speculative maybe.
Add a filter in the url, add the required files from wp-settings and add do_action('rest_api_init')
Untried.
if ( ! filter_input( INPUT_GET, 'shortinit' ) ) {
define( 'SHORTINIT', true );
}
require_once __DIR__ . '/wp-load.php';
...
do_action('rest_api_init')
Related
I am using WP for the first time. I'm just trying to create a very basic script to echo the user's id and am having all sorts of issues.
The code is this and is currently located in wp-content/plugins (i'm not really sure where these things should be):
<?php
require_once ABSPATH . '/wp-includes/pluggable.php';
$user = wp_get_current_user();
echo $user->get_site_id();
I'd had it without the require initially but I was getting a function not defined error for wp_get_current_user. Now I'm getting Warning: Use of undefined constant ABSPATH - assumed 'ABSPATH'...
Is there some sort of predefined set of files that I need to include or some specific directory I need to be putting my scripts so that these variables and functions are in scope? My understanding was that these things are supposed to be global.
Did you try code like that:
add_action('init', 'some_function_name');
function some_function_name() {
$user = wp_get_current_user();
echo $user->get_site_id();
}
The WordPress comes with hooks (actions and filters) to let other developers modify either core parts of the WordPress or code from other plugins / themes.
The code I describe in my answer, it is running your code when the whole WordPress , all the Plugins and the theme are loaded, thus you should have by default the wp_get_current_user() function and you should not need to include manually the pluggable.php.
This seems like is going to solve your problem.
Read more on hooks here: https://developer.wordpress.org/plugins/hooks/.
Side note. Keep in mind that in order to run your custom code you should register a proper WordPress plugin and activate it. If you have made a php file in the plugins folder, and you loaded using PHP functions like require/include the plugin probably will not operate as you expect although the source code it could be perfect. To get more details on how to write your own plugin, you could read here: https://developer.wordpress.org/plugins/
I would like to make requests to the WordPress API much faster. My API is implemented in a plugin (using register_rest_route to register my routes). However, since this is a plugin, everything is loaded with it (the child-theme and the theme) and basically a query to this API is taking half a second because of all this useless parts loaded.
Doesn't WordPress API can be used in another way? Since most plugin making use of the WP-API doesn't need any other plugins to be loaded, even less a theme... I don't understand how they could miss that.
Is there anyway to do this?
Yes, it is possible. In one of my plugins where I need the minimal WordPress core (DB without plugins & themes) here is what I do:
<?php
define('SHORTINIT', true); // load minimal WordPress
require_once PATH_TO_WORDPRESS . '/wp-load.php'; // WordPress loader
// use $wpdb here, no plugins or themes were loaded
The PATH_TO_WORDPRESS constant I made up; you just need to point that to the correct path. In plugins for example, it might look like:
require_once dirname(__FILE__) . '/../../../wp-load.php'; // backwards 'plugin-dir/plugins/wp-content'
Setting SHORTINIT to true certainly does help performance a bit.
With WP_DEBUG disabled, the time it takes to bootstrap WordPress are as follows:
Without SHORTINIT: ~0.045 seconds
With SHORTINIT: ~0.0015 seconds
If this is for your own site where you demand performance, you can probably increase this a bit by enabling an OpCache (e.g. APC or PHP OpCache in recent versions).
But I believe the 2 lines of code above to define SHORTINIT and require wp-load.php are what you're looking for.
To clarify, this file is a part of a plugin, but it is called independently of WordPress itself (via Ajax and directly). It never gets included or used by any other parts of the plugin or WP itself.
EDIT: Since the OP is actually concerned with the WP-API, not WordPress in general, I am adding this to address the actual question. I'll leave the original answer content in case it can help someone else.
I did further testing with the WP API and like #David said in his answer, the issue is probably something else.
I loaded up 12 plugins in addition to the rest api, some fairly "large" plugins, and my local install has about 25 themes installed (one active of course). I edited WordPress' index.php file and used microtime(true) to record when everything started, and then edited one of the REST controllers to calculate how long it took from start to getting to the API endpoint.
The result on my system is consistently around 0.0462 - 0.0513 seconds (no PHP OpCache, and no other system load). So it appears bootstrapping all of WordPress has little impact on performance.
If the requests are taking half a second, the bottleneck is elsewhere and cutting out plugins and themes is going to have minimal impact. At least this is what I found.
I think you might be focusing on the wrong issue.
Loading php files is not nearly as slow as reading from your db and this is likely to be your 500ms load time. You should actually look at reducing this anyway (cache wp-options, etc), but what i suggest to you in relation to the api, is to cache the output using a mu-plugin. Using exit we can load output from file and serve that instantly.
Our Method:
1. Create a folder called mu-plugins in the wp-content folder (may already be there)
create a file called api-cache.php
enter this code into your file:
function get_api_cache(){
//dont run if we are calling to cache the file (see later in the code)
if( isset($_GET['cachecall']) && $_GET['cachecall'] === true)
return;
$url = "$_SERVER[REQUEST_URI]";
//do a little error checking
$uri= explode('/',$url);
//we have a array (1st key is blank)
if( $uri[1] !== 'wp-json' || $uri[2] !== 'wp' || $uri[3] !== 'v2'){
return;
}
//lock down the possible endpoints we dont want idiots playing with this...
$allowed_endpoints= array(
'posts'
);
$endpoint= array_pop($uri); // not sure if this is valid or not, is there more structure to some api calls?
if( !in_array( $endpoint, $allowed_endpoints) ){
return;
}
//ok reasonably confident its a api call...
$cache_folder= get_stylesheet_directory().'/api_cache/';
// prob best if not within php server but to get you going
if(! file_exists ( $cache_folder ) ){
mkdir($cache_folder); //warning 777!!
}
/*
* Need to choose a method of control for your cached json files
* you could clear out the folder on update post/ taxonomies etc
* or cron clear out hourly/weekly whatever freq you want
*/
if( file_exists($cache_folder.$endpoint.'.json') ){
$json= file_get_contents($cache_folder.$endpoint.'.json');
header('Content-Type: application/json');
echo $json;
exit;// we need nothing else from php exit
} else {
//make sure there will be no errors etc..
$ch = curl_init();
$url= "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]?cachecall=true";
$timeout= 5;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$json = curl_exec($ch);
curl_close($ch);
file_put_contents($cache_folder.$endpoint.'.json', $json);
}
}
get_api_cache();
Now you should notice a significant difference on your load time on the 2nd load (this first time it is caching the output).
A few disclaimers:
you should read the comments in the code
You need curl
You need to be aware the cache folder is 777, I would strongly suggest you move this away from your theme folder and preferably outside your http accessible files.
There were no catch all hooks to capture the data to be cached, hence i used curl to grab the content, this may change in the future and a hook/filter would improve the process time a bit when creating the cache file.
I have not included a method to update cache files. You need to decide on how often you want to update, a site that gets lots of posts per day and a lot of visits, you might do a cron job to just delete the files (e.g. 3 times a day, hourly, every 10 minutes, etc-- what is a reasonable tradeoff in update time?) or add a hook to save post to only update when your posts change, etc..
add your endpoints to the array for them (you can remove the if statement to allow all endpoints, but then you may have a situation where 404s are being cached!)
You should give this a try this. It is a plug-in that allows you to enable/disable certain plug-ins for post-types, pages and other circumstances.
For the theme part, if you wrote it, it would be easy to add something in the function.php to prevent it from attaching any hooks or filters in the case of an API request.
As a sidenote, couldn't you query de DB directly?
Sorry for my poor english if this is helpful for you.
Put the plugin folder in root wordpress install.
/public_html/my-plugin/my-plugin.php
and include wordpress main file.
require dirname( dirname( __FILE__ ) ).'/wp-load.php';
Or in plugin folder directly access
/public_html/wp-content/plugins/my-plugin/my-plugin.php
require_once dirname(__FILE__) . '/../../../wp-load.php';
Before check wp-load.php file included properly and working.
wp-settings.php file load whole core, plugins and themes files. wordpress is load first mu-plugins files (wp-content/mu-plugins/) and provide after action hook muplugins_loaded. Trigger this action to exit whole other files loaded. You can also find which action hook is provide before muplugins_loaded and stop other files and script execution.
if define constant SHORTINIT before include wp-load.php its includes
some files provide DB,plugin or basic functions. When we want more load core files and not just want load plugins and theme files in this way found a solution.
// file my-plugin.php
//call before include file wp-load.php
global $wp_filter;
$wp_filter = array(
// pass wp hook where to want exit extra wp loaded
'muplugins_loaded' => array(
// prority
1 => array(
// callback function register
'wp_extra_loaded_exit' => array(
'function' => 'wp_extra_loaded_exit',
'accepted_args' => 1
)
)
)
);
function wp_extra_loaded_exit(){
exit;
}
require dirname( dirname( __FILE__ ) ).'/wp-load.php';
// plugin code here.
We check muplugins_loaded hook is define wordpress early you can also find which hook is define before muplugins_loaded then stop this point to after load more wordpress files. -
When you want to test your script open file wp-settings.php and find string muplugins_loaded then echo statement to check.
echo "Wordpress loaded in this point before";
do_action( 'muplugins_loaded' );
echo "After this wordpress not loading"; // Output fail bcz we exit
I am developing plugin in Wordpress. For the plugin, I am suppose to create a settings page.
When I was researching on Creation of Settings page for wordpress plugin. I found that,
these values are normally stored under the wp_options table.
The only issue I am facing is that in my Settings page. I will be adding a lot of parameters.
These parameters that I will be added is not a constant and will changes depending on the
user's wish.
Therefore I thought of creating a separate table for the plugin settings page.
I would like to ask, Is there any disadvantage in doing so?
Thanks in Advance.
You could make use of the wordpress *_option() functions to store arbitrary data for your plugin, you can prefix it with your plugins name to ensure you don't collide with any existing data.
add_option('yourpluginnamehere_optionname','somedefaultdata'))
http://codex.wordpress.org/Options_API
From there you can use...
update_option('yourpluginnamehere_optionname',$somedatahere))
get_option('yourpluginnamehere_optionname');
delete_option('yourpluginnamehere_optionname');
You should also have a register_activation_hook() and register_deactivation_hook() process to create and clean up your plugins options when the plugin is installed/removed.
If you create and manage additional tables yourself, ensure you prefix them to ensure clear separation from the standard word press tables.
Create the appropriate activation/deactivation hooks to assist with plugin maintenance.
The only disadvantage would be that you'll have to manage storing the parameters yourself.
If you use the WP way of doing it, you already have functions do help you. If you want a custom storage, you will most likely have to write your own code to handle it.
<?php
/**
Plugin Name: Curd Meta
*/
require_once "custom_post.php";
require_once "custom_category.php";
require_once "custom_texonomy.php";
require_once "metabox.php";
function curd_enwueue_scripts(){
wp_enqueue_style('plugin-css',plugins_url('assets\css\style.css',__FILE__));
wp_enqueue_script('ajax-script',plugins_url('assets/js/custom.js',__FILE__),array('jquery','jquery-ui-datepicker'),'12345',true);
wp_localize_script( 'ajax-script', 'ajaxobj', array('ajax_url' => admin_url( 'admin-ajax.php' )));
}
add_action('admin_enqueue_scripts','curd_enwueue_scripts');
add_action('admin_menu','my_curd_plugin_setting');
function my_curd_plugin_setting(){
add_menu_page("Curd operation",'Curd','manage_options','curd-meta','my_curd_functions',
"dashicons-facebook-alt",'9');
}
function my_curd_functions(){
}
I need to set up a demo site for users to try a web app before signing up. The demo would be based on production code, however, it would require minor code changes: connection to a demo database, automatic creation/login of a new guest account for each user, etc.
The obvious solution is to replicate my code base as a second demo website and edit as necessary. Keeping the demo code in sync with production code is easy enough by adding a branch in subversion. I'm less than thrilled, however, at the prospect of having to do two updates on my server (production and then demo) every time I push code from development to production.
Initially I thought I might be able to replicate the website through a module. It's unclear if this is possible, however.
Is there a mechanic in Yii to execute an altered version of a website (config file and selected controllers)?
Never do before, so just an idea
solution with few files in other dir
create a separate a demo dir and map it on your demo URL
In this dir put this index.php (may be your .htaccess too)
<?php
$yii=_PRODUCTION_PATH_.'/framework/yii.php';
$config_prod=_PRODUCTION_PATH_.'/protected/config/main.php';
$config_demo=dirname(__FILE__).'/demo_main.php';
require_once($yii);
$config = CMap::mergeArray($config_prod,$config_demo);
Yii::createWebApplication($config)->run();
the demo_main.php override the classes (user, db) to manage a better demo experience:
<?php
return array(
'basePath'=>_PRODUCTION_DIR_.DIRECTORY_SEPARATOR.'..',
'components'=>array(
'user' => array(
// here you override the user class with a DEMO only user
'class'=>'DemoUser',
)
),
solution with all files of prduction site in a different dir
Here follows the index.php in root dir
<?php
$yii='../framework/yii.php';
$configMain = include dirname(__FILE__).'/protected/config/main.php';
$configProd = include dirname(__FILE__).'/protected/config/production.php';
$configDemo = include dirname(__FILE__) . '/protected/config/demo.php';
require_once($yii);
// for the demo version
// instead of the comment can be an *if* or any solution to manage 2 configs
//$config = CMap::mergeArray($configMain,$configProd);
$config = CMap::mergeArray($configMain,$configDemo);
Yii::createWebApplication($config)->run();
demo.php is analogue to "demo_main.php" overridig classes and configs for the demo version of the site.
The testdrive demo app is configured for this - after you install, note the separate index-test.php, and protected/config/test.php.
Unlike #IvanButtinoni's suggestion, you'll need to access index-test.php, instead of index.php, so you may need to modify your .htaccess if you're using clean URLs to allow access to index-test.php.
When I do this, I usually write a custom init in the base controller.php:
public function init() {
// use test layout if using test config
if (isset(Yii::app()->params['test'])) {
$this->layout='//layouts/test';
}
parent::init();
}
Obviously, I have a test parameter in my test.php . . .
The only difference in my two layouts is that one sets the background color to be a bright yellow, just so it's very clear you're on a test site.
If I have understood well (according to the comment answers to original post) then There are several ways. Here is a link that I think can help great deal. It helped me set up and may be will help you!
In Yii 2 it will be inherently supported
http://www.yiiframework.com/wiki/33/
I have a PHP script that is executed by accessing it directly (this is for AJAX output).
I am initializing Joomla Framework variables inside that script this way:
if ($JEXEC_defined==TRUE) {
defined('_JEXEC') OR defined('_VALID_MOS') OR die( 'Restricted access' ); //security reason
$direct_script_access=FALSE;
}
if ($JEXEC_defined==FALSE) {
define( '_JEXEC', 1 );
define( 'DS', DIRECTORY_SEPARATOR );
define('JPATH_BASE', dirname(__FILE__) );
require_once ( JPATH_BASE .DS.'includes'.DS.'defines.php' );
require_once ( JPATH_BASE .DS.'includes'.DS.'framework.php' );
$direct_script_access=TRUE;
// initialize the application
$mainframe =& JFactory::getApplication('site');
$mainframe->initialise();
}
if ($user->username!="") if ($direct_script_access==TRUE) {
//PHP code when script is accessed directly
}
As an output of the script when accessed directly I need to display a Joomla Plugin, for ex:
{valsimplecalendar SRQCMPDT1 }
But instead of displaying the content of the plugin, I get a flat text "{valsimplecalendar SRQCMPDT1 }".
My question: how to initialize plugin system when calling PHP directly?
Edit
I searched the web and found that I need to import the Joomla Plugins:
JPluginHelper::importPlugin('content');
$dispatcher = &JDispatcher::getInstance();
$dispatcher->trigger('onBeforeDisplayContent', array ( & $category, &$params, $limitstart));
But anyway that doesn't make to display plugin content when directly calling PHP script.
This might not be what you are looking for, but I had the same problem with another Joomla plugin called FlashChart Plugin.
The plugin call looks like this:
{flashchart data="10,20,15,30|40,50,12,14"}Samplechart{/flashchart}
So I thought I could run a PHP script using a PHP plugin, calculate the data and just echo out the above string. Wrong! The curly bracket thing is preprocessed by Joomla and when you run PHP you bypass the preprocessor.
My solution was to use the same code that the plugin used to create the charts I wanted. I basically bypassed the plugin preprocessor and did the same thing that the plugin would have done.... which was to output the necessary code to create one of the plugin's flash charts.
I was lucky though because FlashChart Plugin is very object oriented and creating the charts and outputting the swfobject code was easy.
In short, you may have to look in the plugin code and see what it's doing and do the same thing in your PHP code.
Good luck.
Based on your comment I think your question is really "How do I get an AJAX response without surrounding Joomla template HTML".
In this case you may want to read:
For 1.5
AJAX using MooTools
For 1.6+
Xml-rpc changes in Joomla! 1.6
a StackOverflow question that was self answered
Just add at the end of your URL in your ajax call: &format=raw
Content will only be loaded without the rest!
Plugin events should be triggered somehow. Usually they are triggered during routing and dispatching of the app. You can trigger any plugin methods manually using this code:
JPluginHelper::importPlugin('system'); // Load your plug-in group
$dispatcher = JDispatcher::getInstance(); // USe JEventDispatcher for 3.x
$results = $dispatcher->trigger('onAfterInitialise'); // Trigger your custom event
More information: https://docs.joomla.org/Supporting_plugins_in_your_component