Asynkroniset toiminnot WordPressissä

Toisinaan WordPressin kanssa tulee tarvetta tehdä asioita asynkronisesti. Jos joku toimenpide vaatii aikaa ja aiheuttaa odottelua, mutta sen lopputulos ei oikeastaan ole kriittinen juuri tällä hetkellä, käsillä on asia, joka kannattaa ehkä tehdä asynkronisesti.

WordPress mahdollistaa asynkroniset toiminnot Ajax-toiminnallisuuden kautta. Ajax on oikeastaan tarkoitettu javascript-käyttöön, eli tarkoitus on, että javascriptin puolelta lähetellään ajax-pyyntöjä ja vastauksena tulee sitten jotain, joka voidaan esittää, ja näin tehdä dynaamista toimintaa ilman sivunlatauksia.

Ajaxia voi kuitenkin käyttää yleisesti asynkroniseen toimintaan myös PHP:n puolella, etenkin jos kyseessä on vain tarve saada joku toiminto suoritettua välittämättä vastauksista. Relevanssissa tällainen toiminto olisi esimerkiksi PDF-tiedostojen sisällön lukeminen tiedoston lähettämisen yhteydessä. Nykyään se tehdään käyttäjän odottaessa, mikä hidastaa tiedostojen lähettämisen prosessia. Jos sisällön lukeminen tehtäisiinkin asynkronisesti, käyttäjän näkökulmasta prosessi nopeutuisi mukavasti.

Asynkronisen toiminnon käynnistäminen

Aloitetaan siitä, miten asynkroninen toiminto tehdään PHP:ssa. Vastaus kuuluu: samalla tavalla kuin javascriptissä, eli lähettämällä POST-pyyntö WordPressin ajax-osoitteeseen tarvittavien tietojen kera.

Olennaisin tieto lähetyksessä on action, joka kertoo, mikä toiminto suoritetaan. Pyynnön body-osassa on myös syytä lähettää nonce, jolla varmistetaan, että pyyntö on aito. Pyynnön headers-osiossa taas on syytä välittää cookiet.

Oheisella funktiolla voi räiskiä Ajax-toimintoja vaivattomasti. Parametreissä pitää määritellä toiminnon nimi ja lisäksi voi määritellä avain-arvo–pareja, jotka välitetään pyynnön mukana.

Pyyntö lähetetään WordPressin admin-ajax.php-tiedostolle, joka nimestään huolimatta ottaa vastaan sekä frontin että back endin pyynnöt.

/**
 * Launches an asynchronous Ajax action.
 *
 * Makes a wp_remote_post() call with the specific action. Handles nonce
 * verification.
 *
 * @see wp_remove_post()
 * @see wp_create_nonce()
 *
 * @param string $action       The action to trigger (also the name of the
 * nonce).
 * @param array  $payload_args The parameters sent to the action. Defaults to
 * an empty array.
 *
 * @return WP_Error|array The wp_remote_post() response or WP_Error on failure.
 */
function ms_launch_ajax_action( $action, $payload_args = array() ) {
	$cookies = array();
	foreach ( $_COOKIE as $name => $value ) {
		$cookies[] = "$name=" . rawurlencode(
			is_array( $value ) ? wp_json_encode( $value ) : $value
		);
	}
	$default_payload = array(
		'action' => $action,
		'_nonce' => wp_create_nonce( $action ),
	);
	$payload         = array_merge( $default_payload, $payload_args );
	$args            = array(
		'timeout'  => 0.01,
		'blocking' => false,
		'body'     => $payload,
		'headers'  => array(
			'cookie' => implode( '; ', $cookies ),
		),
	);
	$url             = admin_url( 'admin-ajax.php' );
	return wp_remote_post( $url, $args );
}

Yksinkertaisimmillaan siis toiminnon käynnistäminen käy näin:

ms_launch_ajax_action( 'ms_flush_caches' );

Jos tarvitaan parametrejä, homma hoituu vaikkapa näin:

$args = array(
	'post_id'       => $post->ID,
	'attachment_id' => $attachment_id,
);
ms_launch_ajax_action( 'ms_read_pdf_content', $args );

Asynkronisen toiminnon suorittaminen

Jotta Ajax-pyynnöillä voidaan suorittaa omaa koodia, toiminnot täytyy ensinnäkin rekisteröidä:

add_action( 'wp_ajax_TOIMINNON_NIMI', 'ms_asynchronous_action' );
add_action( 'wp_ajax_nopriv_TOIMINNON_NIMI', 'ms_asynchronous_action' );

Toimintokoukku wp_ajax_TOIMINNON_NIMI rekisteröi toiminnon kirjautuneille käyttäjille ja wp_ajax_nopriv_TOIMINNON_NIMI taas kirjautumattomille käyttäjille. Käytä toista tai molempia sen mukaan, mitä tarvitset.

Itse toimintofunktiossa ei ole mitään erityisen konstikasta. Perusrunko näyttää tältä:

function ms_asynchronous_action() {
	if ( ! wp_verify_nonce( $_REQUEST['_nonce'], 'toiminnon_nimi' ) ) {
		wp_die();
	}
  
  	// Tee mitä tarvitsee, parametrit löytyvät $_REQUEST-muuttujasta:
  	ms_do_something( $_REQUEST['post_id'], $_REQUEST['attachment_id'] );
  
	wp_die();
}

Noncen tarkistuksessa käytetty toiminnon nimi pitää olla tietysti sama kuin kutsuttaessa. Lopuksi pitää tehdä siisti lopetus wp_die():llä.

Jos jotain palautusarvoja olisi, ne pitäisi printata ulos JSON-muodossa, mutta tässä kontekstissa palautusarvojen käyttäminen ei oikein toimi, joten se niistä. Tällainen asynkronisuus toimii tehtäviin, jossa riittää, että joku toiminto käynnistetään ja tulokset kirjataan sitten vaikka tietokantaan.

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *

This site uses Akismet to reduce spam. Learn how your comment data is processed.