i've created a woocommerce plugin,
the plugin itself runs perfectly.
However as long as it takes for it to run, i'm experiencing wierd performances issues.
The website is totally inaccessible(both frontend and backend) ONLY from the browser that is logged in and ran the plugin.
Both frontend and backend are loading until the plugin finishes.
to make things even wierder it's working perfectly from another browser.
also this is run on a high-end dedicated server and when it's running the loads on the server are very low.
any clues?
require __DIR__ . '/vendor/autoload.php';
error_reporting(E_ALL);
ini_set('display_errors', 1);
include_once($_SERVER['DOCUMENT_ROOT'].'/wp-config.php');
use Automattic\WooCommerce\Client;
$woocommerce = new Client(woocommerce_api_url, api_key, api_secret,['version' => 'wc/v3','timeout' => '99999',]);
echo '<pre>';
$db = new DBfdr();
$i=0;
$page = 1;
$products = [];
$all_products = [];
do{
try {
$products = $woocommerce->get('products',array('per_page' => 100, 'page' => $page));
} catch(HttpClientException $e) {
die("Can't get products: $e");
}
$all_products = array_merge($all_products,$products);
$page++;
Notes: the DBfdr class contains a simple function for managing pdo connections to the sql server.
That piece of code doesn't look so good, why would you need to make a plugin that externally loads wp then going through Woocommerce Client Api to get the list of products and then cycle all of them to make an if condition.
That would be so much more efficient if you would just pass inside WP standard plugin structure, using global $wpdb class and performing your queries with some join.
That said, the problem you are facing could be solved by adding this before your code:
ignore_user_abort( true );
/* Don't make the request block till we finish, if possible. */
if ( function_exists( 'fastcgi_finish_request' ) && version_compare( phpversion(), '7.0.16', '>=' ) ) {
fastcgi_finish_request();
}
The problems occurs because the wp-config.php is included in the beggining.
wp-config.php in the end has
require_once(ABSPATH . 'wp-settings.php');
which inits some core wordpress functions which in turn "locks" the session.
i managed to fix the issue by removing
include_once($_SERVER['DOCUMENT_ROOT'].'/wp-config.php');
and replacing it with customs defines
Related
I am working on a project where users can check and edit their own data and can also view their invoices.
I am writing the code for this project myself in PHP on my local machine but the invoices are made with the wp-invoice plugin on an existing and working wordpress site that's hosted somewhere else.
I want users to be able to log in to my web-app and then see their invoices that the web-app retreived from the wp-invoice api on the public wordpress site. The documentation for the wp-invoice api can be found here: https://www.usabilitydynamics.com/product/wp-invoice/docs/wp-invoice-api, it uses XML-RPC with which I am not familiar.
XML-RPC uses built-in wordpress functions to use the API. So I also downloaded and installed wordpress on my local machine and almost got it working (i believe). But when I load the wordpress functions into my web-app using "wp-load.php" it redirects me to the wordpress installer which says wordpress is already installed and there is a working wp-config.php file. This is correct because I installed wordpress successfully.
My code:
(This is my only code, there are no other files, functions or classes included using 'include_once')
define("ABSPATH", "C:/wamp64/www/mijnDashboard/WP");
define("WPINC", "/wp-includes");
include_once( ABSPATH . '/wp-load.php' );
include_once( ABSPATH . WPINC . '/class-IXR.php' );
include_once( ABSPATH . WPINC . '/class-wp-http-ixr-client.php' );
$client = new WP_HTTP_IXR_Client( 'http://MyWordpressSiteWithWP-INVOICEinstalled/xmlrpc.php' );
$client->query('wp.invoice', array(
$method = 'get_invoice',
$credentials = array('Username', 'Password'),
$args = array(
'ID' => 1032017043
)
));
$the_invoice = $client->getResponse();
echo "$the_invoice";
echo "hallo";
Result: (it redirected me from my self-written 'dashboard.php' to the wordpress page 'wp-admin/setup-config.php')
Tried solutions:
I searched the web for solutions and some people said it had something to do with my browser cache. I tried another browser and incognito mode in chrome but both got me the same result.
Beside that I tried to load the wordpress functions that I need to use XML-RPC using an other wordpress file called 'wp-blog-header.php' but it got me the same result.
I actually think this is easy to fix but I am new to XML-RPC and API's at all and I don't know how to properly include all wordpress functions in a non-wordpress, self-written file.
Thanks,
Elias
Okay, I figured it out. I didn't use my local machine anymore but I used a webserver instead. There are no errors and I am not being redirected when I load 'wp-load.php'.
It is strange that almost the same code runs fine on a public webserver but not on a local machine. But it's working now so it's fine.
The code: (I used this and uploaded it to the WordPress root directory which contains the other files like wp-config.php etc.)
<?php
define( 'WP_USE_THEMES', false );
require( 'wp-load.php' );
$rootD = $_SERVER['DOCUMENT_ROOT'];
define("ABSPATH", "$rootD/httpdocs");
define("WPINC", "/wp-includes");
include_once( ABSPATH . WPINC . '/class-IXR.php' );
include_once( ABSPATH . WPINC . '/class-wp-http-ixr-client.php' );
$client = new WP_HTTP_IXR_Client( 'http://mywordpresswebsite/xmlrpc.php' );
$client->query('wp.invoice', array(
$method = 'get_invoice',
$credentials = array('username', 'password'),
$args = array(
'ID' => 1032017039
)
));
$the_invoice = $client->getResponse();
foreach ($the_invoice as $key => $value) {
echo "$value";
}
?>
Thanks for all the help.
I have a custom page in my theme where I am creating a post from a different DB table and I want to then make this display inside wordpress as if it were a normal post. It seems to work most of the time, but randomly it seems that the post is modified after i call get_header() and i cant see why.
I have setup a mod rewrite rule in apache to hit a php file and in here i get the data I need and build the php object. I populate the wordpress post object using this function.
function BuildSimplePost($title, $body)
{
require_once( SITEROOT . '/wp-load.php' );
#$post = new WP_Post();
#$post->ID = -1;
$post->post_parent = 0;
$post->post_title = $title;
$post->post_name = "simple-response";
$post->post_excerpt = substr($body, 0, 100);
$post->comment_status = "closed";
$post->ping_status = "closed";
$post->post_type = "page";
$post->post_content = $body;
return $post;
}
Once the post is sorted I then push this post into the wordpress query objects and let the theme do the rest of the work.
$posts = array($post);
$wp_query->posts = $posts;
$wp_query->post_count = count($posts);
$wp_query->found_posts = count($posts);
$wp_query->max_num_pages = 1;
$wp_query->post = $post;
$wp_query->is_404 = 0;
$wp_query->is_singular = 1;
$wp_query->is_single = 1;
$wp_query->page_id = $post->ID;
include get_template_directory()."/external-page.php";
Inside external-page.php there is nothing weird. It is literally a copy of single.php with some html removed. The issue im having is that when get_header(); is called in this file the post is changed to something else. This then triggers a redirect which brings the user to a different page on the site that is part of wordpress.
Anyone know why the get_header method would be causing a redirect like this?
It's hard to tell exactly what's changing up your post. The way I see it, you've got two options:
Keep putting your content back into the post. This is not the WordPress way of solving this problem but it's probably the easier approach. #ArtisticPhoenix's answer above is the right concept but the wrong specific code.
Create a custom post type, which is the WordPress way. #CBroe offered this and the response to your answer to his question should (IMHO) be: "it doesn't matter how complicated your post type is, you should encapsulate it in a CPT if you're using WordPress."
Put your content back
Keep a copy of your post object somewhere and put it back right after anything that changes it. You can create a new global:
global $mypost;
$mypost = BuildSimplePost(...);
If you know the $title and $body parameters, you can just call your function again every time you need it. You could also use a transient, a update_option/get_option call, or several other things.
There are several filters that could be the cuplrit:
The the_post action should change $post. That's the one thing it really does. You may want to sit on top of the hook stack like this: add_filter('the_post', function() { global $post, $mypost; $post = $mypost; }, 10000);
Before the wp object is set up, there are several actions and you run a high likelihood of anything hooked changing $post because it's free game before then. You may have plugins or your theme hooking on: parse_request, parse_query, pre_get_posts, or posts_selection. You may try something like add_filter('parse_request', function() { global $post; $post = $mypost; }, 10000); for each of these filters.
I've seen some plugin developers adding things that change the $post global (and other things they probably shouldn't change) during calls to the actions template_redirect, get_header, loop_start, and after query. Heck, I've done it myself a few times. You could try the same thing with these filters although I'd consider them less suspect.
If that doesn't get your content back, you could try something really dirty, like forcing it in right before the call to the_post. There's no hook for this but if you control the theme it's easy.
The WP Way
I understand that you think that your post is very complicated but I'll offer you this from several years of being neck-deep in WP code: breaking the WP post model is a recipe for heartache. If you're not using posts and you're not using the way they're intended, you probably shouldn't be using WP. There are other frameworks that offer things like user authentication, themeing, database persistence, eventing, REST, etc. without the overhead of WP.
Another way
That having been said, I've used WP in the past because it was part of a requirement that I couldn't control. When my post gets too complicated, I create a wrapper object like so:
class MyPostWrapper {
private $_Post;
private $_Meta = array();
public function __construct($post) {
$this->_Post = get_post($post);
$this->_Meta = $this->_LoadMeta();
}
private function _LoadMeta() {
// Load everything into $_Meta: other tables, options, post meta, etc.
}
public function __get($name) {
if (array_key_exists($name, $this->_Meta))
return $this->_Meta[$name];
}
// Use a similar implementation for __set and __isset.
}
However complicated your post gets, you can manage its lifecycle and all of its trail very easily with a single wrapper.
Then you don't have to worry about who's eating your post. If they are, they probably should be.
I am working on a website running WordPress and woocommerce
I have a custom function to add stuff to the cart which is the following:
function custom_add_products_to_cart(){
WC()->cart->empty_cart();
$request_body = file_get_contents('php://input');
$decoded = json_decode($request_body);
$cartElements = $decoded->addToCart;
foreach ( $cartElements as $product_id ) {
WC()->cart->add_to_cart( $product_id );
}
if ( $decoded->Uid ) {
WC()->session->set( 'uid', $decoded->Uid );
}
die();
};
This is quite a straightforward function. All it does is iterating through a list of products id and launching the default Woocommerce add to cart function.
The issue I've got is that this works perfectly fine on my localhost (also debugging it ut behaves just like expected) but when I try it on a test server it doesn't work.
The function is firing (i tried to print some messages) but the cart is not emptying and the new products are not added.
I check the code, commit and revision, and everything is correct.
What else can it be?
My last thought was on the version of PHP:
my localhost runs 7.1.2 while the test server runs 7.0.22 - can it be the PHP version or not? any idea on what else I could try?
Sorry if I cannot provide much more details but unfortunately there's not much more to add...
Also, I am not posting this to WordPress community for now as I think it's not a WordPress related stuff (nor woocommerce) but rather PHP code (maybe my function is somehow wrong?) or PHP version
Thanks in advance to everyone
i think the problem is here
file_get_contents('php://input');
depending on your PHP configuration, maybe you need to change the allow_url_fopen setting in you php.ini.
You have two ways of getting around it without changing php.ini, one of them is to use fsockopen(), and the other is to use cURL.
I recommend using cURL over file_get_contents() anyways, since it was built for this.
At the end i simply solve this by calling two functions:
the first one empties the cart:
function empty_cart(){
WC()->cart->empty_cart();
}
and the second one carries on adding to the cart:
function custom_add_products_to_cart(){
$request_body = file_get_contents('php://input');
$decoded = json_decode($request_body);
$cartElements = $decoded->addToCart;
foreach ( $cartElements as $product_id ) {
WC()->cart->add_to_cart( $product_id );
}
if ( $decoded->Uid ) {
WC()->session->set( 'uid', $decoded->Uid );
}
die();
};
and it now works properly.
I have wrote a PHP script that grabs the latest forum posts by categories that I want, which works fine and everything, however my problem lies in the actual output of the code itself, previously I was utilizing XenForo and could use their API on external pages no problem, now that we have migrated to IP.Board I am trying to utilize the IPSLib Library in order to use the parsing system so that the posts I have pulled don't show up all messy and with bbcode everywhere.
The code that pulls the information from IP.Board's database works fine, again I'm simply trying to load & use the IPSLib from IP.Board.
My question is how, if possible, can you load the IPSLib in order to utilize the functions provided by the library?
require_once( 'forums/initdata.php' );
require_once( IPS_ROOT_PATH.'/sources/base/ipsRegistry.php' );
require_once( IPS_ROOT_PATH.'/sources/base/ipsController.php' );
$registry = ipsRegistry::instance();
$registry->init();
$classToLoad = IPSLib::loadLibrary( 'forums/admin/sources/classes/text/parser.php', 'classes_text_parser' );
$parser = new $classToLoad();
$parser->set( array( 'parseArea' => 'topics',
'parseBBCode' => true,
'parseHtml' => false,
'parseEmoticons' => true ) );
and finally where the text you want to parse from BBcode -> HTML use:
print $parser->BBCodeToHtml( $toParse );
I've been asked to fix a problem on a wordpress site. The problem is caused by the fact posts should of been used instead of pages. However the site is up and running and quickest option would be to fix the problem using a hack of sorts.
The site has an events section, each event is a page (this is the issue, should really be a post). In order to have upcoming and past events the post date is used, therefore upcoming events has a post status of 'future'.
There's are list page of events which shows them fine by using the correct query_post(). Although the problem arises when you click through to actual event (which is a future page). If your logged in as an Admin then the page shows but if your not logged in you get a 404 page.
Now if they where posts then the "The Future is Now!" plugin would solve this problem. I have a feeling the only way round the problem is to rewrite part of core Wordpress files.
Any advice would be great, I have a lot of experience with Wordpress so even if you can point me in the right direction.
Cheers,
Jason
[Update]
Thanks maiorano84 for your detailed response. In the long run I intend to move them to posts but in the meantime they've requested we fix it asap without changing any urls (today they sent out a mass email with a list of events without checking any links)
Your solution of including post_status future doesn't work in this case as wordpress doesn't get to the stage of loading the template. Something in wordpress core stops it from getting that far. Ideally if they was a hook I could use to override this behavior in the meantime that would be excellent but if it comes to it I will temporarily edit the core files.
[Update 2]
I now know the two functions that need editing or use a hook that relates to them.
First of we is_404() which needs changed to not add future pages as 404
Second we have is_page() need to return true if a page is future
[Update 3]
I've found how to do this in the core. If you go to wp-includes/query.php line 2682. Copy this in instead of the old function it works correct. If you have a better way please let me know. Thanks.
/** Future Pages **/
// Check post status to determine if post should be displayed.
if ( !empty($this->posts) && ($this->is_single || $this->is_page) ) {
$status = get_post_status($this->posts[0]);
$post_status_obj = get_post_status_object($status);;
if ( !$post_status_obj->public ) {
if ( $post_status_obj->protected ) {
$this->is_preview = true;
print_r($status);
if ( 'draft' != $status ) {
$this->posts[0]->post_date = current_time('mysql');
} else {
$this->posts = array();
}
} elseif ( $post_status_obj->private ) {
if ( ! current_user_can($read_cap, $this->posts[0]->ID) )
$this->posts = array();
} else {
$this->posts = array();
}
}
/** END **/
You can actually add a post_status parameter of 'future' to your page queries. You REALLY shouldn't be modifying your core files in order to do what you want. So on your page.php and archive.php templates (or other relevant templates that's controlling your Event display), you can do something like this:
<?php
$params = array('posts_per_page'=>-1, 'post_status'=>'publish,future');
$query = new WP_Query($params);
if($query->have_posts()) : while($query->have_posts()) : $query->the_post();
?>
<!-- YOUR PAGE HTML HERE -->
<?php
endwhile;endif;
wp_reset_postdata();
?>
This is an oversimplification, but using the correct queries in the corresponding files will allow you to display your pages however you like.
More information here: http://codex.wordpress.org/Class_Reference/WP_Query
Another thing worth considering, and I realize that this wasn't a part of your question, but may very well solve your issue:
Why not create a subdomain on your client's server where you can work on fixing everything without interrupting the user experience? You can easily either import the existing database into your development environment, and make all the changes you need without affecting the live version.
Food for thought. My advice would be to nip this in the bud, and convert the pages over to posts as soon as possible, otherwise the website will turn into a giant mess very quickly, but that's your call.
Hope this helps.
UPDATE:
I would still advise against altering the core files, but if it's a last resort until everything gets fixed, then have at it. Here's is a "WP Friendly" solution I think might help:
add_action('wp','future_redirect', 0);
function future_redirect($WP_Object)
{
$page = is_page() ? get_page(get_the_ID()) : false;
if($page && $page->post_status == 'future')
{
wp_redirect(/*YOUR REDIRECT URL*/);
exit();
}
return $WP_Object;
}