• Resolved chcw

    (@chcw)


    Hi,

    I try to use the sample code at https://developer.www.ads-software.com/reference/functions/wp_insert_attachment/ to add an image to post, and use attachment_url_to_postid to verify if the attached image is valid or not, as below.

    When debugging, attachment_url_to_postid will always return 0 for the attachment added via wp_insert_attachment so the validation always fails.

    I try to add an image to media library manually, then the verification will pass. So I think using wp_insert_attachment to insert media must have missed some important steps that cause the error.

    <?php 
    
    include "wp-load.php";
    
    // $filename should be the path to a file in the upload directory.
    $filename = 'C:/wamp64/www/blogs/wp-content/uploads/2024/03/test12.jpg';
    
    // The ID of the post this attachment is for.
    $parent_post_id = 76;
    
    // Check the type of file. We'll use this as the 'post_mime_type'.
    $filetype = wp_check_filetype( basename( $filename ), null );
    
    // Get the path to the upload directory.
    $wp_upload_dir = wp_upload_dir();
    
    // Prepare an array of post data for the attachment.
    $attachment = array(
    	'guid'           => $wp_upload_dir['url'] . '/' . basename( $filename ), 
    	'post_mime_type' => $filetype['type'],
    	'post_title'     => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ),
    	'post_content'   => '',
    	'post_status'    => 'inherit'
    );
    
    // Insert the attachment.
    $attach_id = wp_insert_attachment( $attachment, $filename, $parent_post_id );
    
    // Make sure that this file is included, as wp_generate_attachment_metadata() depends on it.
    require_once( ABSPATH . 'wp-admin/includes/image.php' );
    
    // Generate the metadata for the attachment, and update the database record.
    $attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
    wp_update_attachment_metadata( $attach_id, $attach_data );
    
    set_post_thumbnail( $parent_post_id, $attach_id );
    
    //  Verify the attached image
    $attach_url = wp_get_attachment_image_url($attach_id, 'full');
    $attach_id2 = attachment_url_to_postid($attach_url);
    
    if ($attach_id == $attach_id2)
      echo "Verficiation succeeds!";
    else
      echo "Verficiaton failed!";
    ?>
Viewing 15 replies - 1 through 15 (of 19 total)
  • Moderator bcworkz

    (@bcworkz)

    I suspect a race condition is preventing expected results. The query for attachment_url_to_postid() runs before wp_insert_attachment() is finished writing its data. SQL INSERT writes take a lot longer time than PHP execution and SQL SELECT reads take.

    You can verify by calling attachment_url_to_postid() again with the exact same parameters, but in a separate request. I think this time it’ll return the expected ID.

    BTW, we’re not supposed to use include "wp-load.php"; to initialize the WP environment because it’s not necessarily portable to other installations. If this is for your own site and your code is not intended to be used by others, do as you wish. But including wp-load.php in a plugin intended for the WP repository will be cause for rejection.

    Thread Starter chcw

    (@chcw)

    Hi, @bcworkz

    Thank you. I try again. Add image attachment. Then wait for 5 minutes and verify it. But attachment_url_to_postid still returns 0.

    Also thank you for your advice on wp-load.php, I write an individual script(not plugin), and if not include wp-load.php, I will get function not existing errors on all WP functions, so have to include it.

    Moderator bcworkz

    (@bcworkz)

    Sorry, I’m not sure what the problem might be then. The image is in fact correctly added, right? Indicating your method of verification might be flawed. I don’t know in what way though. I would think verifying the return from wp_insert_attachment() is not 0 or WP_Error would be adequate verification. You don’t actually do that. IMO that sort of check would be more efficient and preferable.

    Yes, you do get an undefined function error if you do not load the WP environment. It’s just that doing so with wp-load.php is frowned upon due to portability issues. The proper way to initiate the WP environment is actually quite limited. Your options are described in this article. The first few paragraphs make it sound like wp-load.php is just fine, but keep reading, it’s not fine (even though it does work).

    Thread Starter chcw

    (@chcw)

    Hi, @bcworkz

    Thank you very much for such a detailed reply.

    Actually, my verification is just a simple demonstration showing that function attachment_url_to_postid will return 0 for images attached via wp_insert_attachment. My actual purpose is to write a simple script to replace the existing image in a post automatically. So I want to get the alt text, title and desc of the existing image from its URL and use these for the new image. Below is the code:

    	$attachment_post_id = attachment_url_to_postid(esc_url($image_full_size_url));
    
    	if ($attachment_post_id)
    	{
    		$attachment_post = get_post($attachment_post_id);
    
    		//	Get alt text, title and description of the source image
    		if ($attachment_post)
    		{
    			//	We need single value so pass true for $single
    			$image_alt_text = get_post_meta($attachment_post_id, '_wp_attachment_image_alt', true);
    			$image_title = $attachment_post->post_title;
    			$image_description = $attachment_post->post_content;	
    
    		}
              }
    
    Moderator bcworkz

    (@bcworkz)

    Curses you! Now you’ve gotten me curious about this ?? I tested your code on my site. For some unknown reason it appears to execute twice! The first time through everything works and success is reported. The second time through it fails because the source image no longer exists in its original location.

    So now there’s a new mystery. Why the second execution? I wonder if you invoked the WP environment the “right” way (per the article I linked to previously) if behavior would be different. I think it’d be easiest to adapt your code by making it into its own plugin and to use the admin-post.php method. This means making your code into an action hook callback.

    An odd quirk of some action hooks is they can fire more than once per request, so it is sometimes necessary to have your callback execute remove_action() on itself to remove it from the call stack. This needs to be done first thing due to a different sort of race condition. It may not be necessary for admin-post.php, but the possibility exists.

    Thread Starter chcw

    (@chcw)

    Hi, @bcworkz

    I read the article you recommend:

    Yes, you do get an undefined function error if you do not load the WP environment. It’s just that doing so with wp-load.php is frowned upon due to portability issues. The proper way to initiate the WP environment is actually quite limited. Your options are described in this article. The first few paragraphs make it sound like wp-load.php is just fine, but keep reading, it’s not fine (even though it does work).

    For my case, I write a single php file, for example, batchupdateposts.php and put it under the website root public_html folder, and let it to perform tasks in batch that WP interface does not provide. So when I need to run the php file, I will visit https://www.example.com/batchupdateposts.php?nocache=432432. Is this a correct way to do so?

    Actually I get the idea from this post: https://stackoverflow.com/questions/3464701/export-list-of-pretty-permalinks-and-post-title/3474698#3474698

    So now there’s a new mystery. Why the second execution? I wonder if you invoked the WP environment the “right” way (per the article I linked to previously) if behavior would be different. I think it’d be easiest to adapt your code by making it into its own plugin and to use the admin-post.php method. This means making your code into an action hook callback.

    Actually I don’t know how to create plugin, so a single PHP file that can perform the task is enough for me if it works.

    Thank you again for your kind helps.

    • This reply was modified 8 months, 1 week ago by chcw.
    Moderator bcworkz

    (@bcworkz)

    Directly requesting your .php file and including wp-load.php is considered to be Doing It Wrong? ?? While it will work on your site, it might not work on my site. Plugins will work on any WP site.

    Creating a plugin is pretty simple, it’s just a matter of adding the correct comment header to your file and saving the file in /wp-content/plugins/. Making requests through admin-post.php is more involved, but if you’re familiar with Ajax in WP it’s the same concept.

    But if what you have works for you, I cannot blame you if you do not wish to make the additional effort. I cannot promise that doing so would solve the two pass problem. While the failure message is misleading, your code does work correctly on the first pass through. It’s also technically correct on the second pass. It’s not obvious there is a second pass or why it happens at all.

    Thread Starter chcw

    (@chcw)

    Hi, @bcworkz

    Directly requesting your .php file and including wp-load.php is considered to be Doing It Wrong? 

     While it will work on your site, it might not work on my site. Plugins will work on any WP site.

    Thank you. Other than the script is not portable, is there any other issues that may related to direct request .php file with wp-load.php included? I have many such scripts, so if they have issues, we need to rewrite them all.

    • This reply was modified 8 months, 1 week ago by chcw.
    Moderator bcworkz

    (@bcworkz)

    No other issues I know of. The double execution bit is strange but it’ll likely happen if you did it all the “right” way anyway. No need to change everything unless you’re keen to learn how to do this the “right” way ??

    TBH the “wrong” way is still likely to work on 90% (wild guess based on no data) of installations.

    Thread Starter chcw

    (@chcw)

    Hi, @bcworkz

    Thank you very much for all your helps. Do you know a good sample or template of a plugin that contain all the required files? Normally I would like to modified on an existing sample or template so to learn it quickly.

    Moderator bcworkz

    (@bcworkz)

    If your code is all in one file, then your plugin can be one file as well. Single file plugins can reside in /plugins/, they don’t need their own folder within.

    I think you’re over thinking how complex this might be ?? All that’s needed is a simple comment header in a file placed in /plugins/ and you have a plugin. An example of a simple one file plugin is Hello Dolly. But even Hello Dolly is more complex than necessary.

    Where things get a little tricky is integrating your code into Ajax or admin-post.php. If you don’t need much user interaction nor a WP themed response, I suggest the admin-post.php approach. Its use is not very well documented though. The article I linked to earlier is probably as good as any.

    You can pretty much use your existing code as-is, except it’ll need to be made into an action callback function. Of course no need to include wp-load.php. Likely do not need to require image.php either. Instead of directly requesting your file, you would instead request something like example.com/wp-admin/admin-post.php?action=update_my_posts.

    The action you’d add your callback to would then be “admin_post_update_my_posts”.

    Thread Starter chcw

    (@chcw)

    Hi, @bcworkz

    Thank you very much. I will try to do so. Originally I think a plugin needs a suite of php/js/css files.

    Thread Starter chcw

    (@chcw)

    Hi, @bcworkz

    I study the page you give me carefully: https://glennmessersmith.com/pages/wpenviro.html#useapost

    I have a question regarding the following codes:

    // enqueue stylesheet when test page is requested
    add_action('wp_enqueue_scripts', 'bcw_load_css');
    function bcw_load_css() {
    	$queried_object = get_queried_object();			// some requests do not result in an object
    	if ( $queried_object && 1427 == $queried_object->ID )	// only enqueue for an actual object and test page ID 1427
    		wp_enqueue_style('dynotest', admin_url('admin-post.php?action=bcw_dyno'), array(), '0.10a');
    }
     
    // output the CSS 'file'
    add_action('admin_post_bcw_dyno', 'bcw_send_css');
    add_action('admin_post_nopriv_bcw_dyno', 'bcw_send_css');
    function bcw_send_css() {
    	header('Content-type: text/css');
            ...
    	return;
    }

    Why it does not put the line like below to load the CSS directly?(Instead, it invoke bcw_load_css, then bcw_load_css send a request to load bcw_send_css, why borther to do so?):

    add_action('wp_enqueue_scripts', 'bcw_send_css');
    Thread Starter chcw

    (@chcw)

    Hi, Hi,?@bcworkz

    I create a very simple plugin, as below:

    <?php
    
    /*
     * Plugin Name: CCW Test
     */
     
    add_action('admin_post_dnip_hello_world', 'dnip_hello_world');
    add_action('admin_post_nopriv_dnip_hello_world', 'dnip_hello_world');
    
    function dnip_hello_world() 
    {
    	 echo "Hello, World!"	
    }

    Then invoke it via GET request as below:

    https://www.datanumen.com/license/wp-admin/admin-post.php?action=dnip_hello_world

    But get a empty page with error in the title.

    I try to activate the plugin in the plugin list, but also get an error.

    Plugin could not be activated because it triggered a fatal error.
    Moderator bcworkz

    (@bcworkz)

    Your echo line is missing the terminal ; ?? I cannot tell you how often I make this kind of error even though I should know better.

    why borther to do so?

    Because then you can use WP functions to dynamically determine certain CSS values that could not be known ahead of time. I cannot think of a good use case right now, but it’s sort of beside the point. It’s just an example of what’s possible. Maybe it’s not even a CSS file, maybe the DB gets updated by adding media attachments ??

Viewing 15 replies - 1 through 15 (of 19 total)
  • The topic ‘Image added via wp_insert_attachment is invalid?’ is closed to new replies.