2
\$\begingroup\$

I am using a WordPress multisite network and want to pull information from options pages in Advanced Custom Fields to create a json file. I currently have this code running whenever an options field is updated on a subsite. The json file lives on the main site.

The code works and runs successfully, however, it takes forever and often results in 502 errors due to running out of time. This is solved by refreshing the page and attempting to update the options value again.

How can I optimize my code and make it run faster or more efficiently?

functions.php

require_once( 'httpful.phar' );

function create_locations_json( $post_id ) {
    // check if acf field updated is on options page
    if ($post_id == 'options' || $post_id == 0) {
        $stageurl = array();
        $posts = array();
        $args = array(
            'public'     => true,
            'limit'      => 500
        );

        // get all public sites in multisite network
        $sites = wp_get_sites($args);
        foreach ($sites as $site) {
            // loop through sites and pull stage variable from options
            switch_to_blog($site['blog_id']);
            $stage = get_field('stage', 'option');
            if (isset($stage)) {
                $stageurl[] = $site['domain'];
            }
            restore_current_blog();
        }

        // loop through sites to generate json content
        foreach ($stageurl as $i => $stages) {
            $mainurl = parse_url(network_site_url());

            // check if http (local) or https (production)
            if($mainurl['scheme'] == 'https'){
                $url = "https://" . $stageurl[$i] . "/wp-json/acf/v2/options";
            } else {
                $url = $stageurl[$i] . "/wp-json/acf/v2/options";
            }

            // send api url to Httpful to get acf json
            $response = \Httpful\Request::get($url)->send();

            // get fields from acf json
            $name = "{$response->body->acf->small_location_name}";
            $sitestatus = "{$response->body->acf->stage}";
            $city = "{$response->body->acf->city}";
            $state = "{$response->body->acf->state}";
            $email = "{$response->body->acf->email}";

            // get lat and lng from google maps api
            $mapsurl = "https://maps.googleapis.com/maps/api/geocode/json?address=" . urlencode($city) . ",+" . $state . "&key=KEYHERE";
            $mapsresponse = \Httpful\Request::get($mapsurl)->send();
            $lat = "{$mapsresponse->body->results[0]->geometry->location->lat}";
            $lng = "{$mapsresponse->body->results[0]->geometry->location->lng}";

            // create different json responses based on stage
            if ($sitestatus > 1) {
                $address = "{$response->body->acf->address_1}";
                $address2 = "{$response->body->acf->address_2}";
                $postal = "{$response->body->acf->zip}";

                $posts[] = array('id' => $i, 'name' => $name, 'site_status' => $sitestatus, 'address' => $address, 'address_2' => $address2, 'city' => $city, 'state' => $state, 'postal' => $postal, 'lat' => $lat, 'lng' => $lng, 'email' => $email, 'web' => $stageurl[$i]);
            }
            else {
                $posts[] = array('id' => $i, 'name' => $name, 'site_status' => $sitestatus, 'city' => $city, 'state' => $state, 'lat' => $lat, 'lng' => $lng, 'email' => $email, 'web' => $stageurl[$i]);
            }
        }

        // overwrite whole json file with new array
        file_put_contents(plugin_dir_path( __FILE__ ) . '../library/json/locations.json', json_encode($posts));
    }
    else {
        return $post_id;
    }

    return $post_id;
}

// run when acf field is updated
add_action('acf/save_post', 'create_locations_json', 20);
\$\endgroup\$
1
\$\begingroup\$

Your problem is likely making those API requests in a loop. You might consider using a REST library which can support multiple concurrent calls to your end services (perhaps something based on curl_multi_exec()). This would allow you to collapse overall API request time down to the length of whichever request happens to take the longest.

I am not familiar with Httpful which it seems you are using, but in glancing at the information available for that library, I didn't see support for making concurrent requests. This may mean you need to change libraries or build something yourself to do this.

I will link to an example class I had once written in PHP to give you an idea for how this may be accomplished.

https://github.com/mikecbrant/php-rest-client

You are free to use it if you find it useful.

\$\endgroup\$

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.