WordPress.org

Ready to get started?Download WordPress

Forums

[resolved] How does the priority parameter work? (26 posts)

  1. Strictly Software
    Member
    Posted 9 months ago #

    I have written 2 plugins that I use in conjunction with each other, Strictly AutoTags which automatically scans a post (usually imported from a feed) for relevant tags and then adds them, reformats the post and re-saves it (deeplinking, bold etc) - and Strictly TweetBot which allows you to automatically Tweet to multiple accounts OR the same account with different tweet formats. The usual trick is to use the post tags as #hashtags in the Tweet.

    The priority for the AutoTag plugin is 1 e.g add_action('save_post' , array(&$this, 'SaveAutoTags'),1);

    The priority for the Tweetbot plugin is 999 and on the publish (as I only want to Tweet when the post article goes live and not on drafts etc) e.g add_action( 'publish_post', array(&$this, 'PostTweets') , 999);

    However I have noticed recently that I am getting lots of articles added with tags but the tweets are using their default #hashtags NOT the post tags they are supposed to.

    I can remove the custom field I set that says the tweet has been sent, and re-publish the post and if the article has already got tags then I will get a new Twitter post (as long as it's not a duplicate) that contains the correct hash tags.

    E.G two examples from my horse racing site today

    The first one was sent at 5:35pm > https://twitter.com/ukhorseracetips/status/395967181042618368

    New #Racing story Stratford blank 4 McCoy on http://bit.ly/HrN2Gu #HorseRacing #RacingNews

    When I logged in as admin, re-edited and re-published it then I got this tweet > https://twitter.com/ukhorseracetips/status/395976580842807296

    Stratford blank for AP McCoy > http://bit.ly/HrN2Gu #Stratford #APMcoy #Jezki #NationalHunt

    As you can see if you go to the actual article the 2nd tweet is using the post tags attached to the article.

    Everything was working fine up until a few days ago and I cannot think what has changed. I had to turn Omnisearch off on Jetpack due to it causing me issues with one plugin but nothing major has changed.

    Therefore I am thinking that the timings are out e.g the time it takes to scan the post and add the tweets before re-saving the article with new formatted HTML is too long and when the TweetBot plugin does its work there are no post tags for it to use which is why it reverts to the default ones.

    This is why when I re-edit an already tagged post and re-publish the tweets have #hashtags related to the post tags.

    Is the priority setting a real "chain" so if I had a job at 1 and another at 999 (like my 2 plugins) the 2nd job won't even start running until any previous jobs have finished or is it a more parallel process OR even just a time based job e.g the priority 1 job starts 1 ms after publishing whilst the 999 job starts 999 ms after publishing so if the 1st job isn't finished tough luck?

    I am just wondering what has happened here?

    Any help much appreciated.

  2. bcworkz
    Member
    Posted 9 months ago #

    I've no idea what's causing your problem, but I can explain filter priority. The filter callbacks are stored in the global $wp_filter. The top level keys are the filter tags, followed by priority number, the lowest level key is the callback function. The data stored is the callback function string and the number of arguments.

    When apply_filter() is called, all array elements under the tag name key are sorted by the priority key, priority 1s are thus above priority 999. A do/while loop is executed on the priority key elements, so all priority 1s are processed before moving on to the next priority. For all callbacks of the same priority, they are each called in turn in a foreach loop where call_user_func() is applied to each callback.

    I don't know enough of multi-threading server architecture to authoritatively answer your question, but I know enough to hazard a reasonable guess. It is certainly not time based. I don't believe it is totally linear, call_user_func() AFAIK does not need a return for the loop to continue and call the next callback. Nor do I believe it is completely parallel. The threads are not limitless. Once the pipeline is filled, a new thread cannot start until one is available.

    Depending on what other filters are hooked to the same tag, it is conceivable for a 999 callback to begin execution nearly in parallel to a 1 callback. The 1 callback may have been called first, but the 999 callback could conceivably begin execution only a ms afterwards, well before the 1 callback has completed.

    Something else to consider is if some sort of caching is involved, the cache may not be appropriately updated before some value is pulled from it.

    Another possibility, though unlikely, is if you have upgraded to 3.7, you may have been auto-upgraded to 3.7.1. That may coincide with when your problems started. Mind you, this is very unlikely. Minor upgrades have been extremely smooth, causing virtually no issues, which is why auto-upgrades were implemented after careful consideration.

    If the completion of one filter is dependent on the completion of another, you could create a custom action and hook the dependent callback to that action instead of the same filter. Thus the dependent callback cannot start until a do_action() call is only made after some important procedure is completed in the first callback.

  3. Strictly Software
    Member
    Posted 9 months ago #

    Hi

    Thanks for replying, By the sounds of it it seems that it's a not a total sequential process with every function in the array to be run waiting on a return / error code from that method before carrying on with futher functions.

    The problem is that these are 2 seperate plugins so putting in a hook for one to wait for the other would either have to be an option for the user to select (if they used both plugins) or I could combine the plugins into one plugin. Whatever I need the TweetBot code to RUN after the AutoTagging code has completed and not before completion..

    Do you know how other plugin developers develop their code to work with other plugins?

    E.G I know with WP Super Cache (which I use) there are some other plugins it works with like WP Touch or Bad Behaviour.

    Does the WP Super Cache plugin do database lookups for specific tables and values or is there a WordPress array of "plugins" that can be searched to find "active" or "de-active" plugins installed by the user?

    If so that would be great as I could just offer an option and then check for the existence of the other plugin and if it exists make the TweetBot run after the AutoTagging has finished 100%. I could still do it with custom wp_option values I suppose but an array of "plugins" and related metadata would be good,

    I think its down to to the the number of tags a site has as the more articles, the more tags which means more searching and reformatting of the text which causes the tagging process to take longer hence when TweetBot runs no tags exist EVEN if they do later when viewing the article.

    I still get occassions when they both work together fine and the tweet contains relevant new post tags as #hashtags but I have no idea what causes these posts to work and the majority of others not to and hence fall back on the default tweet options.

    Basially I need the WP system to run the priority system sequentially and if it doesn't do this I am going to have to come up with a workaround.

    By the wsy I am still on WP 3.6.1. I've been in Iceland for a while (sorry for the late reply) so I haven't had a chance to reply or play about with installations. You help is much appreciated and any other Z|
    Thanks

    Rob

  4. Strictly Software
    Member
    Posted 9 months ago #

    Hi

    Just to let you know I have done some testing by running a feed import which would take the article from the feed, scan it with plugin 1(priority 1) Strictly AutoTags and add relevant tags then (should) run plugin 2 (priority 999) to send off the tweets.

    The TweetBot when it should be using post tags it coming up blank for them and instead using the default tags. I can only presume this is due to the tagging not having been completed at the time of sending out the tweet.

    Therefore a workaround is required to ensure anyone with both plugins can get the TweetBot to run AFTER any taggng is done. Otherwise you are risking not getting the tags used as #hashtags in the tweets.

    Not everyone has both plugins installed so I either combine the two or somehow "check" which other plugins are installed so I can do your hook suggestion or use a temporary option value (scheduled timrt) to ensure the 2nd plugin only runs after that timer doesn't exist, eg set it when the 1st plugin runs, destory on finish then run the 2nd plugin.

    All ideas welcome.

    Thanks

  5. bcworkz
    Member
    Posted 9 months ago #

    There is an array of active plugins, it's stored in the options table under the key 'active_plugins'. If the plugin causing issues is in this array, then you know additional measures are needed to properly integrate.

    I don't think there's an easy answer to proper integration, it depends on the specifics of the conflict. There's no standard way to know when a foreign hook callback has completed execution. However, if you examine the callback source code, there may be something it does that could act as a signal that it's nearing completion. Perhaps the developer was kind enough to provide a filter hook similar to what we often see at the end of WP core functions :)

  6. Strictly Software
    Member
    Posted 9 months ago #

    Well seeing I am the developer of both plugins I am thinking of just creating some wp_option values that will let both plugins know of each others existence first.

    Then if the AutoTag plugin exists I can add an action once the tagging is complete and then the TweetBot plugin can hook into it and only run when that action fires.

    Be much simpler than merging the plugins.

    Cheers!

  7. Strictly Software
    Member
    Posted 9 months ago #

    Hi

    I don't suppose you know if there is a way of determining within functions hooked to the save_post action whether the article being saved is also being published at the same time?

    The problem I have is that at the moment I am doing my tagging on the save_post action hook so that you can get tags as a draft, edit or remove/add them before publishing the article.

    However if I add a hook to the publish_post action (even with a higher priority) it runs BEFORE the save_post functions.

    Therefore as I only want to Tweet when the post is being published and not when it's just being saved as a draft I need to know the type of save being done.

    I thought save_post would run before publish but it doesn't seem to be that way.

    I had some code to set an option (with the post id of the article being tagged in the name) and then in the publish hook a check for it so that if the tagging was still going on I would sleep for a bit (in a loop) until the tagging was complete before calling the "finished_tagging" action which would delete the option. Only on deletion (completion of the tagging) would my TweetBot run its job.

    However because publish runs before save for some reason this doesn't work as on the first loop iteration the check for the option_[postID] is always false (as its not been created yet) so it thinks the tagging has finished BEFORE its even started.

    Therefore I need a way of knowing that the save_post is going to publish the article not just save a private/draft version - within the save_post action itself.

    Having the code run on multiple actions is problematic as it means the tagging runs multiple times e.g save/publish/post_syndicated_item and obviously I only want to tag it once. Then set some sort of flag to let my other plugin know I am publishing (if I am) so it can tweet.

    Hope you get my drift.

    Thanks

  8. bcworkz
    Member
    Posted 9 months ago #

    I get your drift, though perhaps not the finer points, which may not matter. I think there is something like what you're looking for, more on that in a bit. First, what do you think of this approach:

    The tweet plugin checks for the existence of an active tagging plugin. If not found, no problem, do the tweet thing on publish. If the tagging plugin is active, only do the tweet thing when a particular action on the tagging plugin fires, which only happens when the tagging process is complete?

    So in pseudocode, the tagging plugin would be:

    do_tagging stuff();
    do_action('ssm_done_tagging');

    And the tweet plugin in pseudocode:

    if ( tagging_plugin_installed()) add_action('ssm_done_tagging', 'do_tweet_stuff');
       else do_tweet_stuff();
    function do_tweet_stuff() {
       //actually do the tweet stuff!
    }

    Regardless if you use my idea or not, you will want to ensure to only tweet on a single publish action. As it is, 'save_post' can fire multiple times for one 'Publish' click, so hooking 'save_post' could result in multiple tweets, very bad!

    One way around this appears to be checking for certain conditions before doing anything. I just recently found this logic in a 'save_post' callback for saving meta box values:

    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
          return $post_id;
    //code continues to save meta values

    This appears to allow code to execute only once when hooked into 'save_post' but I haven't tested this. Unlike tweets, there's no bad side effects from saving a value more than once.

    Before finding that snippet, I had been using status transitions to run code only once on initial publish and not on updates. I don't know if you would want to retweet on updates, which would still happen on 'save_post' even with the AUTOSAVE logic. To only run code on the initial publish, hook the action 'draft_to_publish'. For other status variations hook 'transition_post_status' and inspect the old and new statuses (statii?) passed for a particular event. See the source code for wp_transition_post_status() to see how the statuses get worked into various action tags. You should surely find something that works for you. Even then, it may be worth including the AUTOSAVE logic as well.

  9. Strictly Software
    Member
    Posted 9 months ago #

    Hi

    Thanks for getting back to me so quickly.

    I have just thought something that maybe causing the problem. However I don't want to debug WP or re-instal old versions of WP to prove it one way or another.

    The Tagging Plugin always runs on Save Post. However by default the plugin is set to ignore posts that already have tags against them so that you can choose to add your own tags. Therefore as soon as a post gets tags any future edits/saves wouldn't re-scan and tag it.

    However there is an option in admin that can be enabled to remove any existing tags and clean the HTML (remove links/bolding etc) before re-tagging them on every save (I recommend this to be off but it can be enabled). So basically the plugin prevents re-tagging every time the post is edited/saved.

    The Tweet Plugin however runs on Publish Post.

    It uses a custom field once a tweet has been posted so that it knows not to re-tweet an article if it's already been tweeted. You can delete this obviously but remember Twitter also returns a "duplicate post" error message to prevent duplicate tweets being made to an account.

    Therefore as my previous comment stated the publish post action seemed to run BEFORE the save post action (from the debug) which would explain why no tags existed when the Tweet code ran.

    I am just wondering IF in recent versions WordPress has changed their code so that the order or these 2 actions has either changed or become a parallel process rather than sequential. I.E it always used to run in this order SavePost then PublishPost which allowed my tagging to finish before tweeting. However now they run side by side when an article is being published.

    Another thing could be that maybe I have hit some kind of limit in the number of tags that can be handled and scanned in a quick amount of time. My system has 4680 tags so the code could be taking long to run that number of regular expressions. So 3500 tags was fine but 4000 is too long in the time expected of it.

    This would also explain why when I go in as Admin, delete my Tweet custom field and re-save the published article, the Tweet goes out with hash tags made from my post tags DUE to the tags already existing.

    I do like your idea of adding actions as I was just going to use transients or set/delete_option('currently_tagging_[post_id]'); whilst tagging an article (set one at start, delete at end, all unique as they use the ID field from wp_posts.)

    I could then in my TweetBot check for this option value using get_transient/option and if its found, loop, wait, check, loop, wait... up to X times with a X second delay in the loop. Another option would be just to set a custom field once the post was auto tagged (even if no tags were found) so that the Tweet plugin does a similar loop/check/wait until this option appears. It can then delete it after tweeting (in case someone wanted to re-tag their posts - remember the tweetbot has its own field telling us whether a tweet was sent or not)

    This would mean that if the post didn't have tags or was in the process of tagging it wouldn't tweet until it DID have tags OR got to the end of the loop/wait iteration where it would use the default tags/categories.

    I always assumed publish post would be after save post (on new articles) but it seems that this is not the case so I obviously need a way of knowing whether its a publish or just a save and to make my publish functions run AFTER any save methods.

  10. Strictly Software
    Member
    Posted 9 months ago #

    I find the WP terminolog for adding hooks and actions quite hard to understand sometimes, especially when reading other peoples "how to" articles. If they used common terminology such as "creating custom events" or running functions when WP events are fired like "onpublish" "onsave" etc then it would translate easier (for me at least :) )

    Therefore this code is split across both plugins and just involves the Tag plugin creating a new EVENT "on" finished_doing_tagging which gets fired when the Tag plugin has finished tagging.

    The Tweet plugin needs to run ONLY and ALWAYS just on the "on" publish event. The logic decides whether it runs ASAP (if no tagging plugin exists) OR hooks into the "on" finished_doing_tagging EVENT before running the code to send Tweets out.

    // in my Tagging class in the method that tags the posts
    // tag them and save a flag
    public function save_tags( $post_id = null, $post_data = null ) {
    
    	global $wpdb;
    
    	$object = get_post($post_id);
    	if ( $object == false || $object == null ) {
    		return false;
    	}
    
    	// run my tagging code to add tags to the post
    	do_tagging($object);
    
    	// finished so set the custom field up
    	// so we know that we have already tweeted this post
    	add_post_meta($object->ID, 'strictlytweetbot_posted_tweet', '1', true);
    
    	// fire my custom event so any plugin wanting to run when tagging is completed can now do so
    	do_action('finished_doing_tagging');
    
    }
    
    Then in my TweetBot class I need to define <strong>which EVENT to use</strong> as our trigger for sending Tweets out.
    
    As as we only ever want to tweet on publishing an article not saving a draft we always and only ever call a function attached to the publish_post EVENT as this will determine whether to just carry on tweeting OR to wait for our new EVENT finished_doing_tagging before tweeting anything.
    
    public function __construct()
    {
    	// only ever want to tweet on a publish EVENT so always need to hook code into the event "ON" PUBLISH POST
    	add_action( 'publish_post', array(&$this, 'check_and_post_tweets') , 999);		
    
    }
    
    // always ensure the right method is called
    // if tagging plugin is active wait until tagging has finished and run the send tweet code if tags exist are
    protected function check_and_post_tweets($post_id = null, $post_data = null )
    {
    	global $wpdb;
    
    	// ensure we can get post ino
    	$object = get_post($post_id);
    	if ( $object == false || $object == null ) {
    		return false;
    	}
    
    	// check whether my tag plugin is installed and active by checking the array of active plugins and we havent tweeted already
    	if (is_plugin_active('strictly-autotags/strictlyautotags.class.php') && get_post_meta($post_id, 'posted_tweet', true) !== '1') {
    
    		// hook post_tweets into our finished_doing_tagging EVENT
    		add_action('finished_doing_tagging',array(&$this, 'post_tweets'),99);		
    
    	}else{
    		// just run normal tweet code
    		$this->post_tweets(array(&$this, 'post_tweets'));
    	}
    }
    
    // function to run when the EVENT finished_doing_tagging is fired OR no tagging plugin is running - it sends tweets out
    public function post_tweets($post_id = 0) {
    
    	// get info about the post
    	if($post_id == 0){
    
    		// no post ID!!!
    		return false;
    
    	// already tweeted for this post? If so exit
    	}else if(get_post_meta($post_id, 'posted_tweet', true) == '1'){
    
    		// post meta data says we have already posted so until custom field is deleted we cannot tweet again for this post
    		return false;
    	}
    
    	// format the tweet (more complex than this obviously)
    	$tweet = "blah #blah";
    
    	// call method that sends the tweet out
    	$this->send_tweet($tweet);
    
    	// update meta against tbis post so we know that we have already tweeted this post in case multiple events fire off
    	add_post_meta($post_id, 'strictlytweetbot_posted_tweet', '1', true);
    }

    What do you think? Can you see any potential problems with this?

  11. bcworkz
    Member
    Posted 9 months ago #

    Actually, 'publish_post' fires before 'save_post', but there is literally two lines of code between the two, so the firings could be virtually simultaneous. The two lines are other do_action() calls, so depending what's hooked in, there could in reality be some time between the two on some installations. It's been this way as long as I've been involved with WP, v3.0 or so. For your own sanity, you should assume both callbacks are called simultaneously and structure your code accordingly. Even if the reality is different, this mental model should lead to workable code.

    I do see some potential issues, perhaps not really problems. First, are you sure 'publish_post' only fires on initial post? My recollection is different, but I don't recollect so well sometimes. Sounds like you've insured that even if it did, things would work out, which is wise insurance I think.

    In your tagging script you indicate you are adding meta to signify tweeting has been completed. Surely you mean tagging has been completed?

    I think it would be more efficient to decide whether to hook 'publish_post' or 'finished_doing_tagging' in __construct(). No need to go through 'publish_post' again if doing tagging, as 'finished_doing_tagging' is essentially fired by 'publish_post' in the tagging module. (or is it, it's not quite clear?) Your way is functionally the same, just not as efficient in my eyes. I do realize the tagging is not always run, but there is always a callback execution to see if tagging should be done or not. It is the end of that routine where 'finished_doing_tagging' should be fired. Maybe it's not 'publish_post' but 'save_post', as long as you've protected against multiple tweeting for the same post in a way beyond selecting the correct action, it doesn't matter much which action is the initial instigator of the whole process.

    I agree WP terminology leaves something to be desired. 'Event' is much more understandable to most coders instead of 'action hook'. And adding an event listener makes more sense than hooking a filter. But once understood, using the correct terminology goes a long ways when communicating with others. When someone says "this is my action hook" I know exactly what sort of code snippet they are presenting. If the were to say "this is my event listener" I may still understand, but there would be significant doubt in my mind that the person really knows what they are talking about.

    While such jargon is unfortunate for general communication, it does serve as sort of a secret handshake for coders that says "Hey, I'm cool, you don't have to coddle me like some noob, I know whats going on." How people present their problem is all I have to go on for deciding at what expertise level I should respond with. You can imagine, I've many times seriously misjudged so the next response is some variation of "Saaayyy whaaaa???" :D

  12. Strictly Software
    Member
    Posted 9 months ago #

    Hi

    Yes you are sort of right. I basically confused things by putting

    a) code from two different plugins (tweet & autotag) into the same example code.

    b) the custom field you mentioned was copied n pasted from the tweetbot plugin and I was going to use it to note whether tagging has completed but now I don't need it. Also I forgot to change the name so it would have confused anyone reading it.

    Basically I have got the two plugins working together and seamlessly (so no-one has to tick any boxes etc)

    If the AutoTag plugin exists and is active then it shows in the admin panel with a disabled checkbox.

    Basically I have just done this.

    Strictly AutoTags Plugin

    I have just added a new EVENT / Action into the SaveAutoTags method that actually runs on SavePost (as you may want a draft and edit the tags before publishing). If tags already exist it fires straight away and if tagging has to be carried out it the event is fired at the end of the tagging.

    I have passed the Post ID in as a parameter as I see this is the only way that hooks can get the data they need without storing options etc.

    // fire in case tweetbot needs to tweet
    do_action('finished_doing_tagging', $object->ID);

    Strictly TweetBot Plugin

    I have changed the code fired on the publish event to call a new function that determines what action to take when an article is published.

    By the way you are right I have put checks in to ensure tweets are not repeatedly fired including setting a custom field when they are, checks for dupes and of course Twitter usually prevents dupes now anyway.

    This function does the following

    a) checks whether a tweet can be sent in the first place by checking for a valid post ID, that the article is not a private post and ensure a tweet hasn't already been sent by looking for my "posted_tweet" custom field.

    b) if the AutoTag plugin is active and the article hasn't been tweeted already then we wait for our "finished_doing_tagging" event/action to fire before running our post tweets method. If we have no tagging plugin we just run it ASAP.

    // called on on_publish e.g
    add_action( 'publish_post', array($this, 'CheckAndPostTweets') , 999);
    
    public function CheckAndPostTweets($post_id = 0){
    
    	// can we post a tweet anyway? Ensure post is valid
    	if($this->CanWePostTweets($post_id)){
    
    		// check whether my tag plugin is installed and active by checking the array of active plugins also double check we havent tweeted already
    		if (is_plugin_active('strictly-autotags/strictlyautotags.class.php') && get_post_meta($post_id, 'strictlytweetbot_posted_tweet', true) !== '1') {
    
    			// hook post_tweets into our finished_doing_tagging EVENT and wait til this fires before posting our tweets
    			add_action('finished_doing_tagging',array($this, 'PostTweets'),99,1);			
    
    		}else{
    			// no Strictly AutoTags so just post tweets now using either categories/post tags/default #hashtags
    			$this->PostTweets($post_id);
    		}
    	}
    
    	return;
    }

    Therefore if the plugins need to run together they now run in the right order (tag the post -> send the tweets).

    You are right publish does seem to run before save so I needed this hack to get the two to run in the right order as most of my tweets use automatically generated post tags in their tweets as #hashtags.

    It is all working now anyway. You are right about the wording but coming from a C# and JavaScript background I am used to using the words event as it makes more sense to me.

    -being able to run functions "on" an event that exists in the system onclick, onchange onblah etc

    -being able to create your own custom events like ontweet or ontagged onblah that can then be hooked into like standard events etc

    Preference and semantics I suppose.

    Thanks for your help anyway. The two are working together at the moment and I am just running it over night to see how they work together. At the moment all my Tweets which were using default #hashtags due to publish running before Save are now all using the post tags created by my AutoTag plugin.

    It was all working up until a few weeks ago so I guess either a new version of WP (I only updated to 3.7.1 today by the way, straight from 3.6.1) or some limit / time / memory / cpu used by tagging articles and scanning them with thousands of tags (using regex) must have been breached.

    It happens all the time in SQL, you use a @temp table variable and it works a treat in a stored proc for a while until the data being put into it gets too large and suddenly the proc takes forever to run. Answer = swap to a proper table/temporary table and add indexes etc.

    Just a pain that I had to do it when it was working fine but it had to be done I suppose.

    Thanks for your help.

  13. Strictly Software
    Member
    Posted 9 months ago #

    Hi

    Just a follow up. I have checked after a nights running however I have found something out.

    This code I have done all seems to work fine when I am logged in as admin and either posting new articles myself OR running the import feed button from a custom WP-O-Matic plugin I put together.

    However when an automated call to fire off feed imports runs (a WGET request from my server to my site with a special key) the articles get loaded but no tags get added and therefore no tweets go out.

    The WP-O-Matic plugin adds new articles to the system with this code

    $postid = $this->insertPost($wpdb->escape($title), $wpdb->escape($content), $date, $categories, $campaign->posttype, $campaign->authorid, $campaign->allowpings, $campaign->comment_status, $meta);

    which in turn calls

    function insertPost($title, $content, $timestamp = null, $category = null, $status = 'draft', $authorid = null, $allowpings = true, $comment_status = 'open', $meta = array())
      {
        $date = ($timestamp) ? gmdate('Y-m-d H:i:s', $timestamp + (get_option('gmt_offset') * 3600)) : null;
        $postid = wp_insert_post(array(
        	'post_title' 	            => $title,
      		'post_content'  	        => $content,
      		'post_content_filtered'  	=> $content,
      		'post_category'           => $category,
      		'post_status' 	          => $status,
      		'post_author'             => $authorid,
      		'post_date'               => $date,
      		'comment_status'          => $comment_status,
      		'ping_status'             => $allowpings
        ));
    
    		foreach($meta as $key => $value)
    			$this->insertPostMeta($postid, $key, $value);			
    
    		return $postid;
      }

    I am guessing wp_insert_post triggers all the events/actions which are then hooked into.

    Again - this all used to work together without a problem so I don't know what has changed. However as on one site most of my articles are imported automatically I am obviously getting no tags / tweets.

    The code above is fired whether the feed is imported OR run manually by myself from admin. So in theory (unless I don't know something) this shouldn't matter and the same logical flow should happen.

    Feed Import -> Insert Article Post -> Fire Events -> Tagging Fires on SavePost -> Tweeting waits for the finished_doing_tagging event before tweeting -> tweets are sent out.

    I am just wondering if some admin / security changes have occurred or something which might be effecting this. I know I haven't put code in my plugins to prevent automated calls to them affecting their behaviour.

    However I can only assume some sort of security issue is blocking this from happening somehow.

    Any ideas?

    Thanks for your help on this!

  14. Strictly Software
    Member
    Posted 9 months ago #

    I don't know what is making this happen. I even set up a test feed with an article and ran the CRON job that fires WP-O-Matic. No tags were added and in the debug log file I created I couldn't see any occurrence of the tagging code going on.

    I have one site that is always adding tags but never in time for the tweetbot to use them - so it uses default tags (older versions of my plugin)

    And now 2 new versions that add tags, use them and tweet them if posting as Admin or running WP-O-Matic Feed Fetcher as admin BUT no tags OR tweets when running automatically.

    WordPress is sooooo much fun to work with!!! Everything was fine and then it all goes tits up!

  15. bcworkz
    Member
    Posted 9 months ago #

    Well, that's no good! 8-O WTF? (Sorry for the slow response, I was away for a few days)

    You are correct, wp_insert_post() is what fires the hooks you are using. Thus it really makes no sense how the posts could be inserted via CRON but your callbacks are not executed. While it wouldn't explain the 'save_post' hook not firing, if WP-O-Matic in any way plays with the post status or type fields in doing what it does, that could interfere with the 'publish_post' action. I'm really at a loss for any other explanation.

    I wouldn't know what else to suggest other than the usual deactivate all plugins, the activate one by one to see which one breaks the process. To take WP-O-Matic out of the equation, create a simple scheduled task that inserts some static post data, the goal being to simply call wp_insert_post() from a CRON job without involving WP-O-Matic, as it could be the problem itself.

  16. Strictly Software
    Member
    Posted 9 months ago #

    I must apologise first for bombarding you with data here but I thought the more info, debug, code etc I gave you the better it would be from your point of view.

    First off I did as you said and created a basic test page that just called wp_insert_post and returned the post ID so I could call it from a CRON or manually from a GET request. The code is below.

    if(isset($_REQUEST['code']) && $_REQUEST['code'] == "test")
    {
    	ShowTestDebug("OK - LETS ROLL");
    
    	ShowTestDebug("load up wordpress");
    
    	// load up wordpress spaghetti
    	require_once($_SERVER["DOCUMENT_ROOT"] . "/wp-config.php");
    
    	//ShowDebug("doing cron");
    
    	global $wpdb;
    
    	// output all the various no cache headers eg pragma
    	nocache_headers();
    
    	$campaign_structure = array('main' => array(), 'rewrites' => array(),
                                      'categories' => array(), 'feeds' => array());
    
    	ShowTestDebug("Set Categories");
    
    	$categories = array();
    
    	// set categories up
    	$catid = get_cat_id("Internet");
    	if($catid > 0){
    		ShowTestDebug("ID for Internet is " . $catid );
    		$categories['categories'] = $catid ;
    	}
    
    	ShowTestDebug("Insert the post");
    
    	$title = "This is a test post! Ignore";
    	$content = "This is some test content CIA and the FBI and the Federal Reserve Bank of America is going to have trouble FED and CIA test ignore!";
    
    	$postid = insertPost($wpdb->escape($title), $wpdb->escape($content), null, $categories, "publish", 721, false, "open", array());
    
    	ShowTestDebug( "should be done");
    
    }else{
    	die("Wrong Code");
    }
    
      /**
       * Writes a post to blog
       *
       *
       * @param   string    $title            Post title
       * @param   string    $content          Post content
       * @param   integer   $timestamp        Post timestamp
       * @param   array     $category         Array of categories
       * @param   string    $status           'draft', 'published' or 'private'
       * @param   integer   $authorid         ID of author.
       * @param   boolean   $allowpings       Allow pings
       * @param   boolean   $comment_status   'open', 'closed', 'registered_only'
       * @param   array     $meta             Meta key / values
       * @return  integer   Created post id
       */
      function insertPost($title, $content, $timestamp = null, $category = null, $status = 'draft', $authorid = null, $allowpings = true, $comment_status = 'open', $meta = array())
      {
    
    	ShowTestDebug("in insertPost");
    
    	$date = ($timestamp) ? gmdate('Y-m-d H:i:s', $timestamp + (get_option('gmt_offset') * 3600)) : null;
    
    	ShowTestDebug("date is " . $date);
    	ShowTestDebug("categories are...");
    	ShowTestDebug($category);
    	ShowTestDebug("post status = " . $status);
    	ShowTestDebug("get post ID after we call wp_insert_post now");
    
    	$postid = wp_insert_post(array(
        	'post_title' 	            => $title,
      		'post_content'  	        => $content,
      		'post_content_filtered'  	=> $content,
      		'post_category'           => $category,
      		'post_status' 	          => $status,
      		'post_author'             => $authorid,
      		'post_date'               => $date,
      		'comment_status'          => $comment_status,
      		'ping_status'             => $allowpings
        ));
    
    	ShowTestDebug("new postID " . $postid );
    
    	return $postid;
    
      }
    
    function ShowTestDebug($msg){
    
    	if(is_array($msg)){
    		print_r($msg);
    	}else if(!empty($msg)){
    		echo htmlspecialchars($msg);
    	}
    	echo "<br />";
    
    }

    With the old code (no hook when the AutoTagging finished for the Tweet to be sent out) the code worked in that

    -It saved a post
    -It tagged it all
    -It sent a tweet although NOT with the post_tags - default tags were used instead (so obviously the action/hook didn't work or it Tweeted before the post was saved)

    The debug on the screen from that test page was the following (just outputting debug from my test file here NOT the AutoTag or Tweet plugins)

    OK - LETS ROLL
    load up wordpress
    IN GetOptions
    cache user agent is NOT null = Mozilla/5.0 (http://www.strictly-software.com) Strictly TweetBot/1.1.2
    Set Categories
    ID for Internet is 111
    Insert the post
    in insertPost
    date is
    categories are...
    Array ( [categories] => 111 )
    post status = publish
    get post ID after we call wp_insert_post now
    new postID 45273
    should be done

    When I put back the code with the hook in my AutoTagging function that the TweetBot should be linked to with my Action/Hook etc

    // fire my custom event so any plugin wanting to run when tagging is completed can now do so pass in the post ID as the parameter so others can use it.

    do_action('finished_doing_tagging', $object->ID);

    The post was saved but with

    -No tags
    -No tweet send at all (either with default fields or tags)
    -No custom field saved to say a tweet had been sent

    The debug on the page is just this

    OK - LETS ROLL
    load up wordpress
    Set Categories
    ID for Internet is 111
    Insert the post
    in insertPost
    date is
    categories are...
    Array ( [categories] => 111 )
    post status = publish
    get post ID after we call wp_insert_post now

    ..notice no post ID??

    I am guessing there might be some timer going on or something and that the code is waiting for the hook before tweeting or bombing out somewhere??

    If I look in my error log file (I am logging both sets of debug to the same file instead of to the screen so I can see whats going on after the fact)

    I can see that both plugins get instantiated A LOT - I guess thats WordPress loading the same plugin files up on every page / or sections of pages even if they are not used etc.

    I also see for my post (which is the correct post ID) this debug

    IN TWEETBOT CONSTRUCT!
    IN GetOptions
    cache user agent is NOT null = Mozilla/5.0 (http://www.strictly-software.com) Strictly TweetBot/1.1.2
    got options
    WE USE AUTOTAG AND POST ON TAG FINISHED
    TweetBot init finished
    IN CheckAndPostTweets for post id 45266
    IN CanWePostTweets 45266
    get post
    ...notice no return value? Every branch of this function has debug so it should return a message e.g

    public function CanWePostTweets($post_id = 0) {
    
    	ShowTweetBotDebug("IN CanWePostTweets $post_id");
    
    	// no post ID? no tweet
    	if($post_id == 0){
    		ShowTweetBotDebug("No post ID!");
    		return false;
    	// already tweeted?
    	}else if(get_post_meta($post_id, 'strictlytweetbot_posted_tweet', true) == '1'){
    		ShowTweetBotDebug("already tweeted this post");
    		return false;
    	}
    
    	// get this far then bombs out???
    	ShowTweetBotDebug("get post");
    
    	// get post
    	$post = get_post($post_id);
    
    	// no post object so go
    	if ( $post == false || $post == null ) {
    		ShowTweetBotDebug("no post object");
    		return false;
    	}
    
    	// check for private posts OR posts added before the plugin was installed
    	if ($post->post_status == 'private'){
    		ShowTweetBotDebug("post is private");
    		return false;
    	}
    
    	// post was before install date - to post update the post date
    	if(!empty($this->install_date) && $post->post_date <= $this->install_date) {
    		ShowTweetBotDebug("before install date");
    		return false;
    	}
    
    	ShowTweetBotDebug("RETURN TRUE");
    
    	return true;
    }

    I can see no mention of the AutoTag plugin running at all for that post.

    However I can see lots of instances of the AutoTag class being initialised but no actual tagging which you would see from a debug message of

    IN SaveAutoTags

    For example this is some of the debug from the file

    IN AutoTag CONSTRUCT!
    CALL SetValues
    SetValues
    finished setting values
    IN TWEETBOT CONSTRUCT!
    IN GetOptions
    cache user agent is NOT null = Mozilla/5.0 (http://www.strictly-software.com) Strictly TweetBot/1.1.2
    got options
    WE USE AUTOTAG AND POST ON TAG FINISHED
    TweetBot init finished
    IN CheckAndPostTweets for post id 45266
    IN CanWePostTweets 45266
    get post
    RETURN TRUE
    returns true
    IN AutoTag CONSTRUCT!
    CALL SetValues
    SetValues
    finished setting values
    IN TWEETBOT CONSTRUCT!
    IN GetOptions
    cache user agent is NOT null = Mozilla/5.0 (http://www.strictly-software.com) Strictly TweetBot/1.1.2
    got options
    WE USE AUTOTAG AND POST ON TAG FINISHED
    TweetBot init finished
    IN AutoTag CONSTRUCT!
    CALL SetValues
    SetValues

    Lots of AutoTweet/TweetBot Init Constructors but no actual tagging going on!

    It's like the SavePost action is not being fired at all! Which would explain why not tags, no tweet and no custom field are being created.

    If I change the debug on both plugins so they output to the screen instead of the file (so I just get debug for this post, auto tagging and tweetbot) when I run the test page I get the following debug (stripped out unimportant stuff like array outputs etc)

    OK - LETS ROLL
    load up wordpress
    IN AutoTag CONSTRUCT!
    CALL SetValues
    SetValues
    finished setting values
    IN TWEETBOT CONSTRUCT!
    IN GetOptions
    cache user agent is NOT null = Mozilla/5.0 (http://www.strictly-software.com) Strictly TweetBot/1.1.2
    got options
    WE USE AUTOTAG AND POST ON TAG FINISHED
    TweetBot init finished
    Set Categories
    ID for Internet is 111
    Insert the post
    in insertPost
    date is
    categories are...
    Array ( [categories] => 111 )
    post status = publish
    get post ID after we call wp_insert_post now
    IN CheckAndPostTweets for post id 45277
    IN CanWePostTweets 45277
    Have we posted tweet already check from get_post_meta returned
    get post
    RETURN TRUE
    returns true

    .. then nothing?

    No Tweets sent
    No tagging done
    No custom field set
    A post is saved though!

    So the the AutoTag init is being fired but there is no mention of the SaveAutoTags method which should be fired by the wp_insert_post function call.

    However if I go into the WP Admin, edit the post at the top of the page I have the AutoTag init debug e.g

    IN AutoTag CONSTRUCT!
    CALL SetValues
    SetValues
    finished setting values

    And if I save the post I get it tagged, a tweet is sent out and a custom field set

    All the debug is below (I commented out as much as I could and bolded important parts)

    IN AutoTag CONSTRUCT!
    CALL SetValues
    SetValues
    finished setting values
    IN TWEETBOT CONSTRUCT!
    IN GetOptions
    cache user agent is NOT null = Mozilla/5.0 (http://www.strictly-software.com) Strictly TweetBot/1.1.2
    got options
    WE USE AUTOTAG AND POST ON TAG FINISHED
    TweetBot init finished
    IN CheckAndPostTweets for post id 45277
    IN CanWePostTweets 45277
    Have we posted tweet already check from get_post_meta returned
    get post
    RETURN TRUE
    returns true
    Strictly AutoTags is loaded so wait until the finished_doing_tagging event fires for 45277
    RETURN from CanWePostTweets
    IN SaveAutoTags post id = 45277
    Do we need to clean any Strictly Goodness?
    IN CheckAndCleanTags
    we have 131 of content
    no tags saved against post
    return 131 of content
    do we deeplink = 1
    We are deep linking for tags that already have 10 posts associaed with them
    SELECT name,slug FROM wp_terms AS a JOIN wp_term_taxonomy AS c ON a.term_id = c.term_id WHERE ( c.taxonomy = 'post_tag' AND c.count >= 10 );
    there are 1883 tags with 10 or more posts against them
    now auto tag
    IN AutoTag
    our title is This is a test post! Ignore
    IN FormatTitle = This is a test post! Ignore
    RETURN = This is a test post Ignore
    we have 0 search tags we found and 3403 tags from the DB
    look inside our title for terms
    our title is 'This is a test post Ignore'
    IN SearchContentForTags This is a test post Ignore - tweak by 1000 tags
    normal tag scan
    now do the tag equiv
    IN SearchContentForTags This is a test post Ignore - tweak by 1000 equiv
    Tag equiv scan
    so we just searched our title now check html
    get other important tags
    now parse our main bit of content
    IN SearchContentForTags This is some test content CIA and the FBI and the Federal Reserve Bank of America is going to have trouble FED and CIA test ignore - tweak by 0 tags
    normal tag scan
    now do the tag equiv
    IN SearchContentForTags This is some test content CIA and the FBI and the Federal Reserve Bank of America is going to have trouble FED and CIA test ignore - tweak by 0 equiv
    Tag equiv scan
    these are the tags we need
    Array ( [CIA] => Array ( [term] => CIA [count] => 2 ) [FED] => Array ( [term] => FED [count] => 1 ) [FBI] => Array ( [term] => FBI [count] => 1 ) [America] => Array ( [term] => America [count] => 1 ) [Federal Reserve Bank] => Array ( [term] => Federal Reserve Bank [count] => 1 ) [Intelligence Agencies] => Array ( [term] => Intelligence Agencies [count] => 2 ) )
    we are adding 6 to the system
    these are the tags we used
    Array ( [0] => CIA [1] => FED [2] => FBI [3] => America [4] => Federal Reserve Bank [5] => Intelligence Agencies )
    we have 6 tags for this post
    need to store existing A tags as we convert links and dont want nested and tag/bold words
    IN StoreContent direction = STORE
    match [youtube video]
    RETURN CONTENT == This is some test content CIA and the FBI and the Federal Reserve Bank of America is going to have trouble FED and CIA test ignore!
    IN StoreContent direction = ADDTOSTORE
    convert text to links
    do we bold auto tags? == true
    call bold or deeplink tags
    lets auto bold tags
    IN AutoBold This is some test content CIA and the FBI and the Federal Reserve Bank of America is going to have trouble FED and CIA test ignore! we have 6 to bold
    lets loop through our post tags
    AutoBold finished look at how it would appear
    BOLDED RETURNS This is some test content <strong class='StrictlyAutoTagBold'>CIA and the <strong class='StrictlyAutoTagBold'>FBI and the <strong class='StrictlyAutoTagBold'>Federal Reserve Bank of <strong class='StrictlyAutoTagBold'>America is going to have trouble <strong class='StrictlyAutoTagBold'>FED and <strong class='StrictlyAutoTagBold'>CIA test ignore!
    auto link tags = 1
    lets auto link
    IN AutoLink
    put stored content back in
    IN StoreContent direction = RETURN
    RETURN CONTENT
    our new content is === This is some test content CIA and the FBI and the <strong class='StrictlyAutoTagBold'>Federal Reserve Bank of America is going to have trouble FED and CIA test ignore!
    SQL is UPDATE wp_posts SET post_content = 'This is some test content CIA and the FBI and the <strong class=\'StrictlyAutoTagBold\'>Federal Reserve Bank of America is going to have trouble FED and CIA test ignore!' WHERE id = 45277;
    should have been updated rows = 1
    after set object terms
    fire actions on finished_doing_tagging with post ID of 45277
    IN PostTweets 45277
    got post title is This is a test post! Ignore
    DO TWEETING

    posting tweet for post: http://www.mywebsite.com/2013/11/this-is-a-test-post-ignore/
    Fire off request to http://www.mywebsite.com/2013/11/this-is-a-test-post-ignore/ with useragent: to try and cache page before Twitter Rush
    Analyse content - type is ALL
    we need to check the content
    do we allow the post =
    Analyse content - type is ANY
    we need to check the content
    do we allow the post =
    Analyse content - type is ANY
    we need to check the content
    do we allow the post =
    Analyse content - type is ALL
    we need to check the content
    do we allow the post =
    Analyse content - type is ANY
    we need to check the content
    do we allow the post =
    do we allow the post = 1
    use post tags
    check 6 terms which we have
    current post title = This is a test post! Ignore
    Tweet Shrink the title for this tweet
    IN TweetShrink This is a test post! Ignore
    shrink with API call to http://tweetshrink.com/shrink?format=string&text=This+is+a+test+post%21+Ignore
    return This is a test post! Ignore
    Strictly Shrink the title for this tweet using text speak
    IN StrictlyShrink This is a test post! Ignore
    current post title = ths is a test post! Ignore
    IN FormatTweet new story on mywebsite %title% %url% %hashtags% ,http://bit.ly/1aOYpEJ, ths is a test post! Ignore, #America #CIA #FBI #FED MaxLen is 137
    IN ReplaceTitleTags ths is a test post! Ignore with #America #CIA #FBI #FED
    loop through tags
    RETURN ths is a test post! Ignore
    does ths is a test post! Ignore have #hashtags
    IN TrimTweet len is 0
    less than 139 chars long so return it now
    send this tweet == new story on mywebsite ths is a test post! Ignore http://bit.ly/1aOYpEJ #America #CIA #FBI #FED to new article for mytweetaccount
    POST TWEET
    tweet sent ok
    SendTweet RETURNS 1
    Save messages
    set a posted tweet custom field with the value 1 for strictlytweetbot_posted_tweet
    END OF AUTOTAG HOOK

    So as you can see this all works fine! From within ADMIN!

    It tags the appropriate words in the article e.g America, CIA, FBI, FED and then uses them in the tweet #America #CIA #FBI #FED

    So whatever is happening is down to something to do with...

    the wp_insert_post not firing SavePost when it is called automatically?

    security preventing certain actions being called? However it did use to work.

    too many tags and a time limit being set somewhere that is being broken preventing the tagging from working EVEN though I set unlimited in that call e.g

    public function SaveAutoTags( $post_id = null, $post_data = null ) {
    
    	set_time_limit(0);
    
    	ShowDebugAutoTag("IN SaveAutoTags post id = " . $post_id);
    
    	global $wpdb;
    
    	$object = get_post($post_id);
    	if ( $object == false || $object == null ) {
    		return false;
    	}
    
    	... tagging code
    }

    something in the CRON job limiting the time?

    something I have done wrong somewhere - in relation to the hooks/actions?

    In the TweetBot init I have this code

    // set a function to run whenever posts are saved that will call our AutoTag function
    // so I can quickly over rule auto-tagging if it's going wrong!
    if(IGNOREAUTOTAG){
    	ShowTweetBotDebug("IGNORE AUTOTAG AND POST TWEETS ASAP");
    	add_action( 'publish_post', array($this, 'PostTweets') , 999);
    }else{
    	ShowTweetBotDebug("WE USE AUTOTAG AND POST ON TAG FINISHED");
    	add_action( 'publish_post', array($this, 'CheckAndPostTweets') , 999);
    }

    Then in the CheckAndPostTweets I have this (which calls the CanWePostTweets function I posted up above)

    /**
     * Checks whether we hook into the AutoTag plugin
     *
     */
    public function CheckAndPostTweets($post_id = 0){
    
    	ShowTweetBotDebug("IN CheckAndPostTweets for post id " . $post_id);
    
    	if($this->CanWePostTweets($post_id)){	
    
    		// check whether my tag plugin is installed and active by checking the array of active plugins and we havent tweeted already
    		if (is_plugin_active('strictly-autotags/strictlyautotags.class.php') && get_post_meta($post_id, 'strictlytweetbot_posted_tweet', true) !== '1') {
    
    			ShowTweetBotDebug("Strictly AutoTags is loaded so wait until the finished_doing_tagging event fires for $post_id");
    
    			// hook post_tweets into our finished_doing_tagging EVENT
    			add_action('finished_doing_tagging',array($this, 'PostTweets'),99,1);			
    
    		}else{
    
    			ShowTweetBotDebug("no Strictly AutoTags and no tags/categories so just post tweets now for $post_id");
    
    			// just run normal tweet code to tweet NOW
    			$this->PostTweets($post_id);
    		}
    
    	}else{
    
    		ShowTweetBotDebug("We dont tweet for this post! CanWePostTweets returns false");
    	}
    
    	ShowTweetBotDebug("RETURN from CanWePostTweets");
    
    	return;
    }

    Is it something to do with how classes are called, objects passed by reference and so on?

    Also what is the best way to init my plugins? I notice from the debug to the log file that these class inits get called A LOT.

    I used to just put this code underneath the bottom of my code to call the class e.g

    class StrictlyAutoTags{
    	..code
    }
    
    // create auto tag object
    $strictlyautotags = new StrictlyAutoTags();

    Now I use a "Control class" with a singleton to try and reduce the amount of calls e.g

    class StrictlyAutoTagControl{
    
    	// global internal object so if one exists we don't keep creating a new object
    	private static $StrictlyAutoTag;
    
    	/**
    	 * Init is called on every page not just when the plugin is activated and creates an instance of my strictly autotag class if it doesn't already exist
    	 *
    	 */
    	public static function Init(){
    
    		// if class object doesn't already exist
    		if(!isset(StrictlyAutoTagControl::$StrictlyAutoTag)){
    			// create object and store for next time
    			StrictlyAutoTagControl::$StrictlyAutoTag = new StrictlyAutoTags();
    		}
    
    	}
    
    	/**
    	 * Called when plugin is deactivated and removes all the settings related to the plugin
    	 *
    	 */
    	public static function Deactivate(){
    		..code
    	}
    
    	/**
    	 * Called when plugin is deactivated and removes all the settings related to the plugin
    	 *
    	 */
    	public static function Activate(){
    		..code
    	}
    
    }
    
    // register my activate hook to setup the plugin
    register_activation_hook(__FILE__, 'StrictlyAutoTagControl::Activate');
    
    // register my deactivate hook to ensure when the plugin is deactivated everything is cleaned up
    register_deactivation_hook(__FILE__, 'StrictlyAutoTagControl::Deactivate');
    
    add_action('init', 'StrictlyAutoTagControl::Init');

    What is the best way of calling plugin objects to prevent them being initialised when they are not needed? Also to keep the correct data within each object as from the log file output there was a lot of class init going on.

    Now I am wondering if it's something to do with the interaction between the way these two classes are calling each other and so on.

    I am almost at the point of throwing my AutoTagging code into my custom WP-O-Matic so that it does the tagging BEFORE it calls wp_insert_post and then any tweets will ALWAYS come after the post is saved.

    Apart from that I am lost for ideas.

    Any thoughts?

  17. Strictly Software
    Member
    Posted 9 months ago #

    Oh and by the way, I don't know if this is important or not but from my first plugin (which I copied some code from another well know plugin as I didn't know how to go about it) I have always added these functions to my funcs.php file just in case WP ever removes add_filters or add_actions.

    if ( !function_exists('add_filters') ) {
    	function add_filters($tags, $function_to_add, $priority = 10, $accepted_args = 1) {
    		if ( is_array($tags) ) {
    			foreach ( (array) $tags as $tag ) {
    				add_filter($tag, $function_to_add, $priority, $accepted_args);
    			}
    			return true;
    		} else {
    			return add_filter($tags, $function_to_add, $priority, $accepted_args);
    		}
    	}
    }
    
    if ( !function_exists('add_actions') ) {
    	function add_actions($tags, $function_to_add, $priority = 10, $accepted_args = 1) {
    		return add_filters($tags, $function_to_add, $priority, $accepted_args);
    	}
    }

    I don't see how this would effect anything but I thought I should let you know in case you know something I don't.

  18. bcworkz
    Member
    Posted 9 months ago #

    Wow! Too much information! :)

    You'll have to excuse me as I didn't study everything in detail. I do think I got the gist of things though, I appreciate the highlighting.

    I think the most significant observation from all this is it works perfectly from admin but not from CRON. This occurs with all plugins deactivated except for the tagging and tweeting ones?

    Maybe you need to simplify even more. Deactivate everything, tags and tweets as well. Create a super simple plugin that hooks 'save_post' and simply error_logs a message. Create a scheduled task that saves a minimal post. Still no error_log message? Then start tracing through whatever code executes scheduled tasks. Something is messing with the filter/action callbacks. Gotta find it.

    If the CRON does leave an error_log message, then incrementally add elements back in until it breaks. Of course, all this is just saying I don't have any ideas either. But it would be important to be able to identify what is causing the problem if at all possible.

    While I do recognize WP is very inefficient in loading all sorts of crud on every single request, I haven't investigated much the best way to mitigate this. My initial thought is to even conditionally include the plugin code in addition to conditionally instantiating the object.

    Of course when the plugin code is loaded, it is too early to decide if the plugin is needed or not, which is probably how we find ourselves here in the first place. The initial scope of my theoretical efficient plugin is to hook wp or init and check if conditions indicate my plugin would be needed. In your case, check for a POST request and the presence of a particular field indicating a WP post publish or update is happening. Only then is the class definition included and an object instantiated.

    This is strictly conceptual, I've no idea if it would really work, it's simply my answer to "What is the most efficient way to invoke plugin functionality?" It came to me as I was typing this response. I've not investigated any feasibility at all.

    You clearly have a handle on debugging, I can't improve much on what you've done. I'll be happy to continue offering any insights I may have on the inner workings of WP. Beyond that, I don't think I am of much help at this point, I am equally mystified.

  19. Strictly Software
    Member
    Posted 9 months ago #

    Don't worry I solved it!

    I thought I had put it in this forum but I must have been speaking to someone else.

    The problem was due to the is_plugin_active function which is only allowed to run when you are logged in AS ADMIN. Which explains everything perfectly (see https://codex.wordpress.org/Function_Reference/is_plugin_active )

    I couldn't run the same code from a CRON / GET request as I wasn't logged in as admin so it bombed out on that line. But when I was in admin posting everything worked as expected.

    I have replaced that line of code with a check for my strictly_auto_tags wp_options array so if it's there I know autotags is installed and can use that instead of the check for the plugin.

    It doesn't solve the question of why so many plugin initialisers are called all the time (lots from the looks of things) which is why I asked the best way to declare objects (singletons or just $myobj = new myobj(); at the bottom of the page)

    Also someone could in theory have the plugin on their system - de-activated which would mean tagging wouldn't run. But I do offer a "uninstall" when de-activating option so that should solve the majority of cases.

    Thanks for your help - although I was pretty sure I replied to it yesterday.

  20. bcworkz
    Member
    Posted 9 months ago #

    Well, that's rather obscure. I reread the function reference and still didn't get you need to be logged in as admin. The need to manually include plugin.php yes, but not logged on as admin.

    I'm glad you found the solution, that could have been seriously crazy making.

    Instead of checking if a plugin is active, could you use function_exists() as a test? If not active, some function for the plugin should not appear to exist.

    All the crud that WP loads for any single request is probably the one biggest thing I dislike about the package. It's not really a problem for my site, I don't get enough traffic, though page loads are still a bit slow for my taste. I just dislike it on principle. It could be a real problem on heavily trafficked sites. Sigh.

  21. Strictly Software
    Member
    Posted 9 months ago #

    Hi

    It does say that the function is only available in the "admin pages" e.g

    NOTE: defined in wp-admin/includes/plugin.php, so this is only available from within the admin pages, and any references to this function must be hooked to admin_init or a later action. If you want to use this function from within a template, you will need to manually require plugin.php, an example is below.

    So I take that as having to be logged in as admin and using the admin_init hook OR including the plugin code.

    I'm not actually sure what within the admin pages logically means which is why I am presuming it is to do with being logged in as an admin AND in the admin area of the site when running the code.

    This would also make perfect sense to why I can post an article OR call WP-O-Matic in admin and the code was working okay but when I called the page in the plugin folder/test page in the root directory from a GET request it bombed out on that function call.

    I did put a reply up (or I thought I did - must have a dupe thread somewhere OR comments not submitting) which showed that when I moved that is_plugin_active code to the top of my test page and just below the

    require_once(require_once($_SERVER["DOCUMENT_ROOT"] . "/wp-config.php");

    That the test GET request was just dying as soon as it got to the is_plugin_active function call.

    This is what made me think the two were related.

    You are right a test for function_exists would probably be better as long as WP load in all plugins before any code can be ran?

    The reason I ask is, if AutoTags was loaded AFTER the tweetbot plugin would function_exists still be able to see all the functions in the AutoTags plugin?

    If WP loads in all the plugins first on every page THEN lets people do stuff with them it would be okay.

    However like you, I really don't see the need to load in every plugin on every page. It really must kill performance to load in plugins that are only related to saving posts on pages where people are just viewing posts AND vice-versa.

    Could WP not have some sort of plugin_use tables/object that the plugin author defined where their plugin (or even each plugin action) was to be used?

    E.G if my autotagging plugin is only used when a post is saved then the code doesn't need to be loaded when a page is displayed.

    Or if code is linked to a button that can only be hit in admin then (e.g to manually rebuild a sitemap) then it doesn't need to load that plugin code in anywhere else in the site.

    This would allow WP to only load in the relevant plugins FOR the actions being carried out rather than ALL of them ALL of the time.

    You are right in that when I made my first plugin and delved under the covers of WP I was horrified at the amount of duplicate function calls and code being run. It must really hurt performance with all the duplication going on. It is also the reason I learnt PHP a few years back.

    I remember my first plugin was a sitemap plugin that I had to write due to getting out of memory errors when it was rebuilt each time.

    The answers I was getting from people was to just increase the memory allowance for it. It seemed like the same functions were being called on every loop iteration (e.g to get permalink structures for categories, tags, posts, pages etc) rather than just getting them once before the loop.

    So I decided to handle the problem myself, learn PHP, and write my own Sitemap plugin. It can either use pure SQL to build up the recordset instead. OR use SQL to get each section (pages, posts, categories, tags) and then PHP to join them together.

    With my plugin (which I still use even though the SEO parts are a bit redundant now due to Google/Bing changing how you can use their search engines to make requests), the maximum number of SQL calls to the WP DB is always 7, this is the case whether you have 1 or 100,000 posts on your site.

    With other plugins (at least at the time I wrote mine) the number of DB calls increased as the number of posts being outputted in the plugin went up.

    I did a little comparison test which you can see here > http://www.strictly-software.com/plugins/strictly-google-sitemap and you can see in the comparison table (about halfway down between my plugin and 2 others) which compares two different permalink structures:

    /%year%/%monthnum%/%category%/%author%/%postname%/%post_id%/
    /%year%/%monthnum%/%postname%/

    That the number of DB calls was constant with my plugin when compared to the others. It also shows the full amount of records (pages, posts, categories, tags which can be listed in the sitemap), Database calls and the amount of memory used for each (a small site and a larger one).

    This was a few years back now when I only had 7000 posts, now I have 40,000+ so it's even more important that I squeeze every bit of performance I can out of the system and any plugins.

    I suppose this is why I do my deep-linking with my AutoTagging plugin on INPUT (when a post is saved) and not on OUTPUT (when it's shown) as it reduces the amount of work needed (you may save once but display it 100,000+ times).

    I also ban 45%+ of all my traffic (bad bots, hackers, spammers, whole country IP ranges, whole Amazon subnets etc, short user-agents etc) to keep the traffic down to legitimate users.

    I need the code to be quickly loaded and optimised and I have had a real nightmare with a LAMP + WP set-up to get it to run as fast as possible without just throwing more RAM+CPU at it. The amount of PERL, BASH, MySQL optimizer tools and so that I have had to learn to get the stats I need is way too much, but then that could be seen as a good thing as they are all new skills for my CV!

    I am used to Windows (.NET C# ASP) and MS SQL (day job) which have beautiful diagnostic tools for improving DB speed, finding missing indexes and logging useful stats. This is why I find the lack of nice visual diagnostic tools on LAMP very poor in comparison.

    I have often thought that a tool that could link a servers load (uptime, CPU, memory, disk swap etc) with the error/access/MySQL slow query log etc so that you could see what URLs/Queries were being hit and by who (IP/Agent) when a CPU or Memory spike, error or connection issue occurred. Or the biggest hitting IP/UserAgent that caused the most errors etc would be FANTASTIC.

    I even got to the stage of nearly attempting to write one myself at one point. However the nearest I got before solving my own issues was writing another system check plugin which doesn't load in all the WP code, copies the DB constants (to keep it quick and not reliant on any WP issues) and it makes scheduled HTTP requests to a site to log Server Load, No of SQL queries running, long queries, connections, time to load the page and some other stats. Then if there is a problem you can set it to auto optimize/repair your tables OR just send a warning email to you if problems are found.

    I still think a tool linking all those log files and server values (CPU/Memory/Load) would be great though!

    I even wrote a 3 stage WordPress survival guide for my own sanity and to help others moving from Microsoft to LAMP >
    3 part WordPress Survival Guide

    Whilst I am glad I now know PHP/MySQL/Linux/Apache etc there is sooo much I would change if I could re-develop the codebase for WordPress but then I have my own day job to keep me busy at the moment!

    Thanks for your help!

  22. Strictly Software
    Member
    Posted 9 months ago #

    Also, I just realised that my answers that I had thought I had sent to you were accidentally sent to someone from Jetpack about a bug I had reported! Too many tabs open I think.

    They are here > http://wordpress.org/support/topic/omnisearch-breaks-strictly-tweetbot?replies=6#post-4876129

  23. bcworkz
    Member
    Posted 9 months ago #

    After re-reading the function reference a couple more times, I don't think the user has anything to do with is_plugin_active(). It has to do with the plugin.php file being loaded or not (What? WP doesn't automatically load everything?) Something in the admin_init process loads this file, which does not happen with wp-cron. I would think if your plugin were to explicitly include this file the function would work even without admin credentials.

    As for using function_exists(), it would not work if it were called during load time. It would need to be called from 'plugins_loaded' or anything afterwards. 'save_post' or 'publish_post' are both plenty late enough.

    I think the problem with WP efficiency comes from it's early roots as strictly an individual blogging app. The load everything approach was OK for that. Because it is highly extensible, it morphed into a CMS platform. It continued to grow organically, piling on added functionality to an ill conceived base. If it were conceived as a CMS platform from the beginning, perhaps it would have organization such as you suggest, as well as tools to ensure it stays efficient.

    The sort of software bloat we've been seeing really pains me. Instead of endeavoring to write more efficient code, the industry is content to simply throw more memory, processors, and bandwidth at the problem. Consumers are forced to pay for the latest bloatware to stay current, and then again for the newer hardware needed to run it.

  24. Strictly Software
    Member
    Posted 9 months ago #

    Yep I know, too many people thow £$ at the problem (hardware/Memory/CPU) instead of actually debugging and solving the issue at the root (usually badly designed code, missing indexes, functions etc). The amount of performance gains I have had just from adding correct indexes or replacing @table variables with proper temporary #tables with indexes has been immense.

    The is_function test is working perfectly. I tried with the plugin de-activated and the tagging didn't run and the tweets went ASAP, plus in the admin page I don't even show the "Automatically linked with Strictly Autotags to ensure tweeting always runs AFTER tagging" if the plugin is de-activated (but not uninstalled).

    So that seems a better solution than checking for an AutoTag get_option value.

    If you notice the comments I accidentally posted on the other thread. I did create a test page that just called wp_insert_post with some test text to check the firing of the save/publish/finished_tagging hooks and it wasn't working at all e.g no tags and no tweets.

    When I put that is_plugin_active code in the page bombed out as soon as it hit it. As soon as I changed that test with function_exists('ShowAutoDebug') - I always have debug functions in all my plugins which contain the core name of the plugin - then it worked fine. So this solution does work.

    I can totally understand a system that starts out as one thing and then morphs into another. Once it reaches a certain size it becomes too large to rebuild from the bottom up and only small fixes/changes can be applied. However if you had enough developers ( I don't know how many Automatic have ) they could work on a new version from the ground up WordPress 2000+ or something that was designed properly with thought for the future, all whilst the existing system continued to run.

    It is what I have had to do 3 times with our companies top selling jobboard software and sometimes it's good to start from scratch just to remove all those old mistakes you know you would never repeat.

    The plugin loading does seem like overkill and I think you have fixed it now but in a version not too long ago on the home page I was having 230+ queries being run when the page loaded. Instead of one big query to get all the posts, categories, tags, meta for the 10/20 posts on a page (or even 10/20 queries to get post/category/tag/meta data per post) it was getting single record queries for each post, category etc in a row all with LIMIT 1,1 on the end. I have no idea why but I am sure a lot of the code could be condensed and network traffic reduced by returning all the data you need in one SQL per page (if possible) rather than 100's of single record SQL calls.

    Anyway it is working perfectly and even though I have had to learn a hell of a lot of PHP/PERL/BASH/LINUX to get WP running fast it has been worth it.

    Thanks for your help

  25. bcworkz
    Member
    Posted 9 months ago #

    You're most welcome. I'm glad my ideas are working well for you. I also enjoyed our OT chat along the way. One parting thought...

    However if you had enough developers ( I don't know how many Automatic have ) they could work on a new version from the ground up WordPress 2000+ or something...

    Wouldn't that be awesome! There's quite a few devs working on WP core code, but they're all or nearly all volunteers. It seems only a few are doing most of the work. I don't see the concerted effort required for a major rewrite happening with this coding model. All their efforts appear to be towards improving the user experience and not towards more efficiency. Improved features is something more people would notice, which keeps the cadre of volunteers excited to be in on the bleeding edge of something. Understandable but unfortunate.

  26. Strictly Software
    Member
    Posted 9 months ago #

    Always good to chat code n swap ideas with another developer!

    Thanks for your help it is all working smoothly now. All my posts are getting tagged correctly from Strictly AutoTags and then all my Tweets are going out using the correct post tags as #HashTags ONCE the event has fired (if both plugins are installed).

    Sweet!

Reply

You must log in to post.

About this Topic