0

My aim is to import all XML files from a folder inside the WordPress installation (/data/*.xml)

To achieve this, I added action in functions.php:

/**
 * Show 'insert posts' button on backend
 */
add_action( "admin_notices", function() {
    echo "<div class='updated'>";
    echo "<p>";
    echo "To insert the posts into the database, click the button to the right.";
    echo "<a class='button button-primary' style='margin:0.25em 1em' href='{$_SERVER["REQUEST_URI"]}&insert_mti_posts'>Insert Posts</a>";
    echo "</p>";
    echo "</div>";
});

Here's my code:

/**
 * Create and insert posts from CSV files
 */
add_action( "admin_init", function() {
    global $wpdb;

    // I'd recommend replacing this with your own code to make sure
    //  the post creation _only_ happens when you want it to.
    if ( ! isset( $_GET["insert_mti_posts"] ) ) {
        return;
    }

    // Change these to whatever you set
    $getposttype = array(
        "custom-post-type" => "cikkek"
    );

    // Get the data from all those XMLs!
    $posts = function() {
        $xmlfiles =  glob( __DIR__ . "/data/*.xml" );
        $data = array();
        $errors = array();

        // Get array of XML files
        foreach ( $xmlfiles as $key=>$xmlfile ) {
            
            $xml = simplexml_load_file($xmlfile);
            $xmldata = json_decode(json_encode($xml), true);
    
            $posttitle = $xmldata['THIR']['CIM'];
            $postlead =  $xmldata['THIR']['LEAD'];
            $postcontent =  $xmldata['THIR']['HIRSZOVEG'];
            
            $data = array(
    
                $key => array(
                
               "title" =>       $posttitle,
               "description" => $postlead,
               "content" =>     $postcontent
                )
                
            );

            $data[] = $post;
    
                };

        if ( ! empty( $errors ) ) {
            // ... do stuff with the errors
        }

        return $data;
        
    };


    // Simple check to see if the current post exists within the
    //  database. This isn't very efficient, but it works.
    $post_exists = function( $title ) use ( $wpdb, $getposttype ) {

    // Get an array of all posts within our custom post type
    $posts = $wpdb->get_col( "SELECT post_title FROM {$wpdb->posts} WHERE post_type = '{$getposttype["custom-post-type"]}'" );

    // Check if the passed title exists in array
    return in_array( $title, $posts );
    };

    foreach ( $posts() as $post ) {

        // If the post exists, skip this post and go to the next one
        if ( $post_exists( $post["title"] ) ) {
            continue;
        }

        // Insert the post into the database
        $post["id"] = wp_insert_post( array(
            "post_title" => $post["title"],
            "post_content" => $post["content"],
            "post_type" => $getposttype["custom-post-type"],
            "post_status" => "draft"
        ));

    }

});

Issue 1:

The code kind of works, but it only inserts the first .XML into the WordPress database. I don't understand why, as I loop through all of them and send back an array.

Issue 2: The code checks the title of the given XML and matches it up against the database -> should not add it if it's the same content. Unfortunately, it does.

Issue 3: I think this is because the admin_init action, but unfortunately, the import runs each time I refresh the admin. I only want it to run, if I click the Insert Posts button in admin. Is there another hook that is better suited for this?

1
  • Your problem isn't a WP problem but a PHP issue. Basically $data = array( replaces $data, it does not add stuff to the array, it sets the array. So rather than adding posts to the array, it's setting the array as if it's a whole new array with 1 item. It has nothing to do with the admin_init hook. As I've said elsewhere in your other question, your use of a closure/anonymous function to read in the data in XML in a loop, then a second loop to create the post massively overcomplicates things. A single loop would be significantly easier to understand/write, more reliable, and faster – Tom J Nowell Feb 17 at 12:50
0

You are doing this to add posts to the $data array:

$data = ...

This is not how you add something to an array. You want to append, not assign.

Think of it like writing a list of 5 things, where for each item you throw the list in the trash, get a new piece of paper, and write the item at the top. At the end you will have a list with only the last item.


As an aside, you've asked several questions about this code, but have not refactored it, even though it is structured in a very complicated way.

Instead, it would be much easier and faster to rewrite it like this:

files = xml files in folder
foreach file
    xmlfile = load the XML file
    if the post does not exist
        wp_insert_post( [ .... stuff from the XML file ... ] )

Instead of what you have right now:

data = empty array
get xml files function 
    files = xml files in folder
    foreach file
        xmlfile = load the XML file
        add the details to an array
        add that array to data
call the get xml files function and for each thing in the array it returns
    if the post does not exist
        call wp_insert_post with the details
0

Thanks for everyones help. I was able to solve it like this:

In the original code I added, the data[] variable did not get filled up with the post data.

This was partially because of syntax errors ($key was not required for example as the loop returned the wrong data).

Also, the XML returned extra spaces, so some regex needed to be added, that is taken care of in the json variable.

Once the data[] variable filled up properly with the XML posts, the import worked flawlessly.

/**
 * Show insert posts button on backend
 */
add_action( "admin_notices", function() {
    echo "<div class='updated'>";
    echo "<p>";
    echo "To insert the posts into the database, click the button to the right.";
    echo "<a class='button button-primary' style='margin:0.25em 1em' href='{$_SERVER["REQUEST_URI"]}&insert_sitepoint_posts'>Insert Posts</a>";
    echo "</p>";
    echo "</div>";
});

/**
 * Create and insert posts from CSV files
 */
add_action( "admin_init", function() {
    global $wpdb;

    // I'd recommend replacing this with your own code to make sure
    //  the post creation _only_ happens when you want it to.
    if ( ! isset( $_GET["insert_sitepoint_posts"] ) ) {
        return;
    }

    // Change these to whatever you set
    $sitepoint = array(

        "custom-post-type" => "cikkek"
    );

    $posts = function() {
        $xmlfiles =  glob( __DIR__ . "/data/*.xml" );
        $data = array();
        $errors = array();

        // Get array of XML files
        foreach ( $xmlfiles as $key=>$xmlfile ) {
            
            $xml = simplexml_load_file($xmlfile);
            $json = preg_replace("/^\s+/", "", json_encode($xml));

        
            $xmldata = json_decode($json, true);
    
            $posttitle = $xmldata['THIR']['CIM'];
            $postlead =  $xmldata['THIR']['LEAD'];
            $postcontent =  $xmldata['THIR']['HIRSZOVEG'];


            $post = array(

                "title" =>       $posttitle,
                "description" => $postlead,
                "content" =>     $postcontent
                
                );

             array_push($data, $post);
    
                };

        if ( ! empty( $errors ) ) {
            // ... do stuff with the errors
        }

        return $data;
        
    };

    // Simple check to see if the current post exists within the
    //  database. This isn't very efficient, but it works.
    $post_exists = function( $title ) use ( $wpdb, $sitepoint ) {

        // Get an array of all posts within our custom post type
        $posts = $wpdb->get_col( "SELECT post_title FROM {$wpdb->posts} WHERE post_type = '{$sitepoint["custom-post-type"]}'" );

        // Check if the passed title exists in array
        return in_array( $title, $posts );
    };

    foreach ( $posts() as $post ) {

        // If the post exists, skip this post and go to the next one
        if ( $post_exists( $post["title"] ) ) {
            continue;
        }

        // Insert the post into the database
        $post["id"] = wp_insert_post( array(
            "post_title" => $post["title"],
            "post_content" => $post["content"],
            "post_type" => $sitepoint["custom-post-type"],
            "post_status" => "draft"
        ));

        
    }

});
2
  • You should describe what you actually did to solve the problem, not just paste all your code. – Jacob Peattie Feb 18 at 5:39
  • Thanks for the heads up Jacob, added an explanation. – Pbalazs89 Feb 19 at 9:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.