Forum Replies Created

Viewing 15 replies - 1 through 15 (of 15 total)
  • Thread Starter cxtinac

    (@cxtinac)

    Thanks @snaacks

    Thread Starter cxtinac

    (@cxtinac)

    To answer my own question, this was caused because I stupidly forgot to set the Host header:
    proxy_set_header Host public.example.com;

    Thread Starter cxtinac

    (@cxtinac)

    UPDATE: Thought I would update anyone still following this, now I’ve had the chance to try the above on a fresh install of 5.9. No plugins except ‘Classic Editor’ and default theme.
    I can confirm that this blockquote behavior is caused by something in my code not the core (as we suspected).

    Thanks for your support @bcworkz

    Thread Starter cxtinac

    (@cxtinac)

    Fair enough, thanks.
    At some point before too long I might get the chance to test this on a clean empty install – if I do I will report back here what I find (so I won’t close it yet).
    Thanks again ??

    Thread Starter cxtinac

    (@cxtinac)

    Thanks @bcworkz

    The posts were imported using the WordPress importer plugin, exported from an older WordPress 4.7 (from memory) site using the WordPress export. Here’s an example of the first few chars of an exported post content XML section:
    <content:encoded><![CDATA[<blockquote><em><p>February 14th is Valentine’s Day, the one time of the year dedicated [...content skipped...] you.</p></em></blockquote>[...remainder of content...]
    The imported content for the post reflects exactly this unchanged.

    If I display that same post using the following (the complete single.php):

    <?php
    	if ( have_posts() ) :
    			/* Start the Loop */
    			while ( have_posts() ) : the_post(); ?>
    				<h2><?php the_title(); ?></h2>
    				<div id="post-<?php the_ID(); ?>">
    					<div><?php the_content(); ?></div>
    				</div>
    			<?php endwhile;
    	endif;

    I get:

    <div id="post-684">
    <div><blockquote><em><p>February 14th is Valentine?s Day, the one time of the year dedicated..[skip].. you.</p></em> [...remainder of post content skipped here....] your options.</em></p><p>&nbsp;</p></blockquote>
    </div>
    </div>

    -note blockquote at the end of the full content.

    If I enabled the filter the blockquote section is terminated correctly.

    As you say, it is probably not worth chasing very hard (I have not tried on a fresh install for example) – but with such a simple template and simple test case it’s hard to see what’s mangling it.

    Thanks again

    Thread Starter cxtinac

    (@cxtinac)

    Fixed.
    The problem was that the custom post type was using a global $post; to get a post ID to operate on when it ran update_post_meta() (old code), and when a new custom post was created it leaked a reference to the prior post, leading to the confusing results I experienced.

    So for me the learning is be exceptionally cautious about scope when using global $post;, especially outside of theme files and the loop!

    Here’s the discussion that put me on to the solution.

    @vijayhardaha @bcworkz thank you very much for your help, advice and support!
    I will update the Status to resolved.

    Thread Starter cxtinac

    (@cxtinac)

    I have rewritten this as a straightforward linear POST handler, and I am getting the exact same behavior. It is added to the Gist here.

    This code blindly adds a new CPT post every time, without checking whether it is a duplicate post or not.

    If I POST identical json twice I get two posts created, both with the meta data correctly populated, as expected. However, if I POST different json the second time the second post is correctly populated, but the first post meta data then gets wiped in the same single POST handling.

    I still worry that I’m missing something fundamental in the way update_post_meta works. It seems like post ID and meta_key are not sufficient selection criteria for the database transaction. Put another way, update_post_meta( int $post_id, string $meta_key, mixed $meta_value ) is using something from its context to decide what to do.

    Edit: clarification

    • This reply was modified 2 years, 10 months ago by cxtinac.
    • This reply was modified 2 years, 10 months ago by cxtinac.
    Thread Starter cxtinac

    (@cxtinac)

    Thank you very much @vijayhardaha I have looked at your Gist.

    These are good cleanup suggestions, I will do this. I guess my question would be do you believe this will help with the original problem? Obviously there are many ways to wrangle the incoming stringified json POST into update_post_meta() calls, but I still have been unable to find any evidence that I’m sending invalid data to update_post_meta() (I wish I had!).

    I am still not able to understand $cpt_meta_fields = (array)$this; this.

    The My_Registry class is a pretty thin wrapper on the $data array anyway, and (array)$this then is a one-line way to get the data array back out, without getting backed in to iterating over dozens of fields by name. The (admittedly small) advantage of actually parsing $data into private fields in the class in the first place is that it will help me cleanly reference individual fields as needed in future code. The object “unpacking” happens in a private method, and obviously values are referenced read-only fwiw.

    There is a detailed discussion of this approach here, in case you have not seen that.
    Hope that helps.

    Thanks again for your advice.

    Thread Starter cxtinac

    (@cxtinac)

    I’ve put what I believe is everything relevant in a Gist.
    A few comments:

    • I’ve included the small awk script I used to remove proprietary / personal info from the example POST json strings. This was run with a final sed cleanup like this – ./awk-cleanup.sh post1.txt | sed 's/,}/}/g' > post1-clean.txt
    • I believe the result is still valid json, but I have not tested that (it’s a fine tradeoff between a good result and writing a custom json parser obviously)
    • I’ve also included the my_dump.php utility that is referenced many times (commented out) in the code
    • I have pasted the cleaned up code without removing my code comments, and also left a few commented lines of code in the hope it might be helpful as well.
    • Sorry for the lengthy turnaround – it took some time to put this all together in a shareable form.

      Edit: One final comment in case it’s relevant, the POST is going to a custom archive page for the Registry CPT;

    • This reply was modified 2 years, 10 months ago by cxtinac.
    Thread Starter cxtinac

    (@cxtinac)

    Thanks @vijayhardaha that’s a good thought.
    Let me look in to that (obviously there’s some private content I have to filter out).

    Thread Starter cxtinac

    (@cxtinac)

    @bcworkz thank you, that is a very interesting thought.

    Briefly the data is in fact POSTed from a nodejs system that receives, parses and scrubs data from external systems before POSTing it to this code.
    I have validated the contents of the json before it gets sent many times as part of this whole debugging process (I do not have an example to hand, but could generate one if it’s helpful).

    Here’s the latest version of the POST handler code (changed slightly from in the original post above, as part of my ongoing efforts):

    // we might be getting POSTed json data from the back end sync
    if ($_SERVER['REQUEST_METHOD'] == "POST"){
    	$json = file_get_contents('php://input');
    	if ($json){
    		$data = json_decode($json, true);
    		$registry = new My_Registry($data);
    		$registry->create_or_update();
    		unset($registry);
    		exit();
    	}
    }

    I think the unset() and exit() are not needed, but not causing further issues.

    I’ve added a debug var_dump() to the _write_meta_value() function above (3 posts up), and that has only ever shown valid data. But having said that, what you describe is exactly consistent with the problem I am having. Here’s the full code that decides whether to create or update. I believe this should always end up with a valid value for $this->registry_cpt_id but I have stared at it so much I may well have missed something:

    function create_or_update(){
    	$post_id = $this->_exists();
    	if ( empty($post_id) ){
    		$post_id = wp_insert_post(array (
    			'post_type' => 'gwc_registry',
    			'post_title' => $this->title,
    			'post_status' => 'publish',
    			'comment_status' => 'closed',
    			'ping_status' => 'closed'
    		));
    	} else {
    		// TODO update existing post title here if necessary
    	}
    	// do we now have a post to work with?
    	if ( ! empty($post_id) ){
    		$this->registry_cpt_id = $post_id;
    		$this->_update_meta();
    	}
    }
    
    private function _exists(){
    	$params = array(
    		'posts_per_page' => 1,//only looking for one hit
    		'post_type' => 'gwc_registry',
    		'meta_key' => 'registry_id',
    		'meta_value' => $this->id
    	);
    	$reg_query = new WP_Query($params);
    	if ($reg_query->have_posts()) {
    		$reg_query->the_post();
    		$post_id = get_the_id();
    		wp_reset_postdata();
    		return $post_id;
    	}
    	return false;
    }

    Unfortunately importing this data from multiple sources (which I have no control over) means there are multiple unique index key fields that need to be preserved. So $this->registry_cpt_id is the WordPress post ID, different from $this->id and $this->registryno.

    Sorry for the long post, and thanks again

    Thread Starter cxtinac

    (@cxtinac)

    Unfortunately this did not resolve the problem. I have cleaned up the code, added empty() checks as suggested and wrapped the call to update_post_meta() in a further check:

    function _write_meta_value( $post_id, $meta_key, $meta_value){
    	if ( ! isset($post_id, $meta_key, $meta_value) )
    		return null; //the only value update_post_meta will NOT return
    	return update_post_meta( $post_id, $meta_key, $meta_value );
    }

    Unfortunately this works exactly the same as the original problem statement.

    I also briefly enabled MariaDB query logging on the development server and for the first of two POSTs from my external script (see above) I get this (MariaDB fieldname backticks removed for clarity):

    2410 Query	INSERT INTO wp_posts (post_author, post_date, post_date_gmt, post_content, post_content_filtered, post_title,......
    2410 Query	INSERT INTO wp_postmeta (post_id, meta_key, meta_value) VALUES (2842, 'registry_id', '378')

    Note post ID 2842.

    For the second of two POSTs I see this:
    2416 Query INSERT INTO wp_posts (post_author, post_date, post_date_gmt, post_content, post_content_filtered, post_title,.......
    Post ID is 2843.
    But then I get:
    2416 Query UPDATE wp_postmeta SET meta_value = NULL WHERE post_id = 2842 AND meta_key = 'registry_id'
    Note this is setting meta to NULL for the previous post 2842!

    I feel I must be misunderstanding something fundamental about update_post_meta (although I have used it many times in the past without encountering anything close to this).

    Is it possible this is a concurrency issue?

    Any and all follow up very welcome.

    Edit: markup not allowed inside code marks

    • This reply was modified 2 years, 10 months ago by cxtinac.
    Thread Starter cxtinac

    (@cxtinac)

    Thank you very much!
    It’s good advice, I will try NULL trapping the updates as you suggest, and check for empty $post_id.

    3. I am not able to understand this line
    $cpt_meta_fields = (array)$this;
    $this is a class object and you’re converting it into an array, doesn’t make sense to me.

    The class in fact contains more than 20 attributes, and I am using this to convert to a key value array, without having to explicitly access each, which I can then pass to the meta update.
    It’s analogous to
    get_object_vars($obj)
    but includes the (many) private attributes.

    Thanks again

    Thread Starter cxtinac

    (@cxtinac)

    Hey Richard, we needed this for a client a couple of months ago, I will check it out again now. Thanks for the update, sounds good!

    cxtinac

    For me it was Easy ToolBox.

Viewing 15 replies - 1 through 15 (of 15 total)