Nauczymy się kilku przydatnych umiejętności przy pisaniu pluginów. Dodamy własne kolumny do zakładek postów i mediów, dodamy własny przycisk do paska administracyjnego, nauczymy się dodawać różne skrypty JavaScript z poziomu pluginu tylko wtedy, gdy tego potrzebujemy.

Tworzymy plugin – standardowa procedura

W naszej instalacji WordPressa mamy folder wp-content, w nim zaś folder plugins. Tam utworzymy folder test-plugin a w nim plik test-plugin.php o następującej treści:

<?php
/**
 * Plugin Name: TEST PLUGIN
 * Description: Learning to write plugins.
 * Version: 1.0
 * Author: Your Name
 */

if (!defined('ABSPATH')) {
    exit;
}

W tym samym folderze potrzebny nam jeszcze plik index.php o takiej treści:

<?php
// Silence is golden.

Są to nasze, dobrze już znane, standardowe procedury bezpieczeństwa.

Teraz nasz plugin możemy włączyć.

Dodajemy przycisk do admin-toolbar – admin_bar_menu hook

Na początek dodamy sobie (w pliku test-plugin.php) przycisk do admin-toolbara, który przeniesie nas na jakąś stronę, niech będzie, że Google. Nie jest to trudne – musimy wykorzystać hook admin_bar_menu:

add_action( 'admin_bar_menu', 'my_custom_admin_bar_button', 100 );

function my_custom_admin_bar_button( $wp_admin_bar ) {
    
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }

   
    $wp_admin_bar->add_menu( array(
        'id'    => 'my-custom-button',
        'title' => 'Mój Guzik',
        'href'  => 'https://www.google.com'
    ) );
}

Funkcja callback przyjmuje API wp_admin_bar, które posiada opcję add_menu. Wcześniej tylko sprawdziliśmy, czy użytkownik może zarządzać opcjami – dla bezpieczeństwa.

No dobrze, ale po co nam taki guzik? Przenoszący nas na stronę Google?

Pewnie po nic.

Możemy jednak chcieć mieć jakiś własny przycisk w pasku admina, który po kliknięciu nie przenosi nas na żadną stronę, ale wykonuje jakąś akcję, zdefiniowaną w pliku JavaScript.

W takim wypadku – nie możemy nigdzie użytkownika (admina) przenosić:

function my_custom_admin_bar_button( $wp_admin_bar ) {
    // Sprawdź uprawnienia użytkownika (np. czy ma dostęp do zarządzania opcjami)
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }

    // Dodaj nowy guzik do paska administracyjnego
    $wp_admin_bar->add_menu( array(
        'id'    => 'my-custom-button',
        'title' => 'Mój Guzik',
        'href'  => false,
    ) );
}

Musimy teraz stworzyć nasz plik admin_btn.js w folderze naszego pluginu:

document.addEventListener("DOMContentLoaded", (event) => {

    var myButton = document.getElementById('wp-admin-bar-my-custom-button');
    console.log(myButton);

    // Dodaj nasłuchiwacz na kliknięcie guzika
    myButton.addEventListener('click', function() {
        // Wyświetl komunikat w konsoli
        console.log('Guzik został kliknięty!');

        // Wyświetl okienko alertu
        alert('Guzik został kliknięty!');
    });

  });
    

Ten plik – tak sobie zakładamy – zostanie zaciągnięty wtedy, gdy pojawia się pasek admina. Czekamy tam, aż drzewo DOM zostanie w pełni załadowane.

Następnie „łapiemy” element o ID 'wp-admin-bar-my-custom-button’ (takie ID ma nasz przycisk, a raczej element <li> oplatający go – możemy to sobie sprawdzić w devtoolsach) i dodajemy do niego event-listener na kliknięcie.

Wewnątrz funkcji callback ustalamy, co się ma dziać po kliknięciu. Teraz wystarczy tylko te console.logi i alerty zastąpić naszym własnym kodem.

Oczywiście, to jeszcze nie wszystko. Przechodzimy do pliku test-plugin.php i dołączamy nasz plik admin_btn.js w następujący sposób:

function wpdocs_selectively_enqueue_admin_script( $hook ) {
    
    wp_enqueue_script( 'my_custom_script', plugin_dir_url( __FILE__ ) . 'admin_btn.js', array(), '1.0' );
}
add_action( 'admin_enqueue_scripts', 'wpdocs_selectively_enqueue_admin_script' );

Teraz po kliknięciu przycisku zobaczymy naszą akcję.

Dodajemy własne kolumny – posty i media

Dodamy sobie teraz kolumnę wyświetlającą ID naszych postów. Potrzebujemy do tego dwóch fragmentów kodu.

Pierwszy, nasza kolumna:

function add_column( $columns ){
	$columns['post_id_clmn'] = 'ID'; 
	return $columns;
}
add_filter('manage_posts_columns', 'add_column', 5);

Drugi fragment – zawartość naszej kolumny:

function column_content( $column, $id ){
	if( $column === 'post_id_clmn')
		echo $id;
}
add_action('manage_posts_custom_column', 'column_content', 5, 2);

To wystarczy, aby zobaczyć nasze kolumny w panelu admina, w zakładce posts.

Teraz przydałaby się jeszcze jedna opcja, a mianowicie sortowanie naszych postów po ID:

add_filter( 'manage_edit-post_sortable_columns', 'sortable_id_column' );
function sortable_id_column( $columns ) {
    $columns['post_id_clmn'] = 'ID';
    return $columns;
}

W przypadku, gdyby trzeba było działać na CPT (custom post types) wyraz post w naszym hooku zamieniamy na nazwę posta. W poprzednich hookach zaś:

  • manage_posts_custom_column zamieniamy na manage_NAZWA_CPT_posts_custom_column
  • manage_posts_columns zamieniamy na manage_NAZWA_CPT_posts_columns

Jeżeli natomiast nie mamy jeszcze pełnej jasności jak to działa, to proponuję wykonać jeszcze jedno ćwiczenie. Tym razem dodamy sobie kolumnę pokazującą ilość wyrazów w naszym poście.

Rzecz pierwsza – dodać taką kolumnę do listy kolumn z odpowiednią nazwą:

function add_column_wc( $columns ){
	$columns['post_wc_clmn'] = 'Wordcount'; 
	return $columns;
}
add_filter('manage_posts_columns', 'add_column_wc', 5);

Rzecz druga – zwrócić jako wartość ilość wyrazów:

function column_content_wc( $column, $id ){
	if( $column === 'post_wc_clmn'){
		$content = get_post_field('post_content', $id);
		echo str_word_count(strip_tags(strip_shortcodes($content)));
	}
		
}
add_action('manage_posts_custom_column', 'column_content_wc', 5, 2);

Możemy już zauważyć, że callback do 'manage_posts_custom_column’ przyjmuje jako drugi argument ID. Dzięki temu – mamy zawartość posta, którą możemy oczyścić z niepotrzebnych tagów i pokazać ilość znaków.

Teraz dodajmy naszą kolumnę do listy podlegających sortowaniu:

add_filter( 'manage_edit-post_sortable_columns', 'sortable_wc_column' );
function sortable_wc_column( $columns ) {
    $columns['post_wc_clmn'] = 'Wordcount';
    return $columns;
}

Powinno wystarczyć, aby zadziałało.

Dodawanie skryptów z poziomu pluginu – różne metody

Z poprzedniego tutoriala możemy pamiętać taki oto kod, który dodawał plik smooth.js:

function smooth_script()
{   
    wp_enqueue_script( 'my_custom_script', plugin_dir_url( __FILE__ ) . 'smooth.js' );
}
add_action('wp_enqueue_scripts', 'smooth_script');

Ten plik działał na wszystkich stronach i zamieniał linki do kotwic na takie, które mają efekt płynnego przejścia:

window.addEventListener('DOMContentLoaded', function(){
    document.querySelectorAll('a[href^="#"]').forEach(anchor => {
        anchor.addEventListener('click', function (e) {
            e.preventDefault();
    
            document.querySelector(this.getAttribute('href')).scrollIntoView({
                behavior: 'smooth'
            });
        });
    });
});

W naszym pluginie skrypty możemy dodawać także w bardziej zaawansowany sposób. Napiszmy sobie plik block-present.js w folderze naszego pluginu:

console.log("Block is present!");

Teraz dodamy sobie ten plik, ale tylko wtedy, gdy post, który przeglądamy widzimy w widoku singular (czyli pojedynczy post, strona pojedynczego posta) oraz ten post ma blok paragraf:

function enqueue_if_block_is_present(){
    if(is_singular()){
       $id = get_the_ID();
       if(has_block('core/paragraph',$id)){
          wp_enqueue_script('my-awesome-script',plugin_dir_url( __FILE__ ) . 'block-present.js' );
       }
    }
  }
  add_action('wp_enqueue_scripts','enqueue_if_block_is_present');

Jeżeli teraz przejdziemy na stronę posta (zakładamy, że paragraf ma) to w konsoli zobaczymy taką akcję, ponieważ nasz plik zostanie załadowany.

Możemy teraz zamienić 'core/paragrapf’ na 'core/button’ (zakładając że post guzika nie posiada) albo np. 'core/blablabla’ i zobaczyć, że plik nie jest ładowany, bo warunek nie został spełniony.

Skoro wiemy już, jak sprawdzać, czy wyświetlamy post na stronie pojedynczego wpisu, oraz wiemy, jakie nasze posty mają ID (napisaliśmy sobie kolumnę w poprzedniej sekcji) to możemy załączyć plik, który odpala się jako skrypt tylko w konkretnym poście.

W moim przypadku będzie to ID równe 24.

Tworzymy w folderze pluginu plik is_24.js:

console.log("Singular post page for post with ID 24");

Oczywiście w naszym przypadku ID może być inne, ale już wiemy, jak możemy je sobie podejrzeć.

Teraz dodajemy nasz skrypt tylko dla wpisu o ID równym 24 i tylko na stronie pojedynczego wpisu:

  function enqueue_if_ID_24(){
    if(is_singular()){
       $id = get_the_ID();
       if($id === 24){
          wp_enqueue_script('my-24-script',plugin_dir_url( __FILE__ ) . 'is_24.js' );
       }
    }
  }
  add_action('wp_enqueue_scripts','enqueue_if_ID_24');

Tylko post o takim ID będzie wyświetlał console.log pochodzący ze skryptu.

Oczywiście możliwości są nieograniczone – możemy sprawdzić, czy post ma thumbnail, ile ma wyrazów, albo cokolwiek, co nam przyjdzie do głowy – i tylko wtedy dołączyć nasz skrypt.

Hook the_content – copyrights i czas czytania posta

Te rzeczy – informację copyrights oraz blok pokazujący, ile czasu będziemy czytać dany post – zrobimy sobie później i lepiej. Na razie jednak wykonamy je sobie w prosty sposób, aby zobrazować, czym jest hook the_content.

Najpierw copyrights – chcemy, aby wyświetlały się nam na samym końcu każdego posta. Użyjemy hooka „the_content”:

  function add_copyrights($content){
    if ( is_singular( 'post' ) && in_the_loop() ) {
		$content .= '<p class="copyrights">Copyrights ' . get_bloginfo('name') . " ". date('Y') . '</p>';
	}
         
    
    return $content;
}
add_filter('the_content', 'add_copyrights');

Bierzemy oryginalną treść i – na stronie pojedynczego wpisu typu 'post’ oraz wewnątrz pętli – dopisujemy do niego <p> z naszymi informacjami.

Zwracamy zmodyfikowaną treść.

Możemy jeszcze na szybko dodać sobie jakieś stylowanie do tej klasy 'copyrights’:

function copyrights_add_styles(){
    echo "<style>
       p.copyrights{
           background: #F55B0C;
           padding: 10px 20px;
           color: #fff;
       }
       </style>";
}
add_action('wp_head', 'copyrights_add_styles');

Nie jest to może najlepszy sposób – ale działa.

Teraz dodajmy sobie informację, jak długo zajmie nam czytanie danego posta. Taka informacja powinna być na początku, nie na końcu – gdy już przeczytaliśmy, to raczej tego nie potrzebujemy.

Pamiętając, że mamy dostęp do treści posta i mając na uwadze, że średnio czytamy 200 słów na minutę, znając wbudowaną w PHP funkcję do zwracania ilości wyrazów, możemy coś takiego napisać:

function reading_time($content){
    if ( is_singular( 'post' ) && in_the_loop() ) {
        $word_count = str_word_count( strip_tags( $content ) );
        $readingTime = ceil($word_count / 200);
        $reading_info = "Szacowany czas czytania (w minutach): $readingTime";

		return '<p class="copyrights">' .  $reading_info . '</p>' . $content;
	}
         
    
    return $content;
}
add_filter('the_content', 'reading_time');

Metabox z własną kolumną – źródło obrazka

Już to kiedyś robiliśmy – piszemy metabox dla źródła obrazka. Upewnijmy się tylko, że w aktualnym projekcie już takiego metaboxa gdzieś nie mamy (w functions.php albo jakimś pluginie).

Zakładam, że nie.

Pierwsza rzecz, której potrzebujemy, to dodanie naszego metaboxa, w panelu po prawej stronie:

function add_image_source_metabox() {
    add_meta_box(
        'image_source_metabox',
        'Image Source',
        'render_image_source_metabox',
        'post', // Post type
        'side', // Context: 'normal', 'side', or 'advanced'
        'default' // Priority: 'high', 'core', 'default', or 'low'
    );
}
add_action( 'add_meta_boxes', 'add_image_source_metabox' );

Szczegółowo już to opisywaliśmy – teraz na szybko lecimy.

Kolejna rzecz – wyrenderowanie naszego metaboxa w panelu po prawej:

function render_image_source_metabox( $post ) {
    // Retrieve the current value of the meta field
    $image_source = get_post_meta( $post->ID, 'image_source', true );
	wp_nonce_field('image_source_meta_box_nonce', 'image_source_meta_box_nonce');
    ?>
    <label for="image_source">Image Source:</label>
    <input type="text" id="image_source" name="image_source" value="<?php echo esc_attr( $image_source ); ?>">
    <?php
}

Korzystamy z nonce (number only used once – taki trochę token CSRF) dla bezpieczeństwa. Nazwa funkcji pochodzi z 3 argumentu, jaki przekazaliśmy do add_meta_box.

Używamy get_post_meta, ponieważ jeżeli nasz post już ma to wypełnione w bazie danych to przy edycji chcemy to widzieć, nie mieć puste pole, nieodpowiadające wypełnionemu w bazie danych.

Teraz już tylko zapisywanie meta-boxa:

function save_image_source_metabox( $post_id ) {
	if (!isset($_POST['image_source_meta_box_nonce'])) {
        return $post_id;
    }

    // Verify that the nonce is valid.
    if (!wp_verify_nonce($_POST['image_source_meta_box_nonce'], 'image_source_meta_box_nonce')) {
        return $post_id;
    }

    // If this is an autosave, our form has not been submitted, so we don't want to do anything.
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return $post_id;
    }

    // Check the user's permissions.
    if ('post' == $_POST['post_type']) {
        if (!current_user_can('edit_post', $post_id)) {
            return $post_id;
        }
    }
    if ( isset( $_POST['image_source'] ) ) {
        update_post_meta( $post_id, 'image_source', sanitize_text_field( $_POST['image_source'] ) );
    }
}
add_action( 'save_post', 'save_image_source_metabox' );

Czyli do akcji save_post podpięliśmy co następuje:

  • sprawdź, czy nonce (token) zostało wysłane
  • sprawdź, czy nonce się zgadza
  • sprawdź, czy nie jest robiony autosave
  • sprawdź, czy typ wpisu to post
    • sprawdź, czy użytkownik może edytować posty
  • sprawdź, czy przesłano nowy image_source, jeżeli tak – zrób update.

Teraz musimy tylko sobie dodać nasze kolumny.

Dodajemy kolumnę do listy kolumn:

function add_column_imgsrc( $columns ){
	$columns['post_imgsrc_clmn'] = 'imgsrc'; 
	return $columns;
}
add_filter('manage_posts_columns', 'add_column_imgsrc', 5);

Sprawiamy, że wyświetla wartość naszego image source:

function column_content_imgsrc( $column, $id ){
	if( $column === 'post_imgsrc_clmn'){
		$image_source = get_post_meta( $id, 'image_source', true );
		echo $image_source;
	}
		
}
add_action('manage_posts_custom_column', 'column_content_imgsrc', 5, 2);

Dodajemy możliwość sortowania naszej kolumny:

add_filter( 'manage_edit-post_sortable_columns', 'imgsrc_sortable_columns');
function imgsrc_sortable_columns( $columns ) {
	$columns['post_imgsrc_clmn'] = 'imgsrc'; 
	return $columns;
}

Własne kolumny dla mediów – oraz jak rozwiązywać problemy

WordPress nie ma najlepszej dokumentacji ani systemu pomocy, a fakt, że ten framework jest tak rozrośnięty i wszechobecny sprawia, że z jednej strony mamy swego rodzaju niedostatek, z drugiej – przesyt, zalewający nas, bardzo często, niepotrzebnymi treściami.

Trzeba mieć smykałkę do kombinowania, oraz cierpliwość i umiejętność wyszukiwania informacji, przeszukiwania internetu – przy jednoczesnym braku przywiązywania się na 100% do czegoś, co ktoś napisał.

Oto nasza kolumna dla wpisów, która pokazuje ich źródło (z metaboxa):

function add_column_imgsrc( $columns ){
	$columns['post_imgsrc_clmn'] = 'imgsrc'; 
	return $columns;
}
add_filter('manage_posts_columns', 'add_column_imgsrc', 5);

function column_content_imgsrc( $column, $id ){
	if( $column === 'post_imgsrc_clmn'){
		$image_source = get_post_meta( $id, 'image_source', true );
		echo $image_source;
	}
		
}
add_action('manage_posts_custom_column', 'column_content_imgsrc', 5, 2);

add_filter( 'manage_edit-post_sortable_columns', 'imgsrc_sortable_columns');
function imgsrc_sortable_columns( $columns ) {
	$columns['post_imgsrc_clmn'] = 'imgsrc'; 
	return $columns;
}

A teraz wyobraźmy sobie, że chcemy zrobić kolumnę ID dla naszych mediów (obrazków i tym podobne). Ja się swego czasu poddałem, nie mając czasu, bo szybciej było mi napisać komponent Reactowo-Wordpressowy, który pozwalał mi podejrzeć ID danego obrazka.

Napisałem też własną stronę, wyświetlającą obrazki oraz ich ID:

if ( ! shortcode_exists( 'media_ids' ) ) {
    function media_ids_shortcode() {
		$args = array(
			'post_type'      => 'attachment',
			'post_mime_type' => 'image',
			'posts_per_page' => -1,
		);
		$images = get_posts($args);
		
		if ($images) {
			ob_start();
			echo '<ul>';
			foreach ($images as $image) {
				$image_id = $image->ID;
				$imageUrl = wp_get_attachment_image_url($image_id, 'thumbnail');
				echo '<li>';
				echo '<img src="' . esc_url($imageUrl) . '" alt="Image">';
				echo ' ID: ' . $image_id;
				echo '</li>';
			}
			echo '</ul>';
		} else {
			echo 'Brak obrazów w bibliotece mediów.';
		}
		$output_string = ob_get_contents();
		ob_end_clean();
		return $output_string;
	}
    add_shortcode('media_ids', 'media_ids_shortcode');
  } 

function mediaID_menu_page() {
    add_menu_page(
        'Media ID',
        'Media ID',
        'manage_options',
        'mediaID',
        'mediaID_page_callback'
    );
}
add_action( 'admin_menu', 'mediaID_menu_page' );

function mediaID_page_callback() {
    echo '<div class="wrap">';
    echo '<h1>Media i ich ID</h1>';
	echo do_shortcode('[media_ids]');
    echo '</div>';
}

Naprawdę, łatwiej to było zrobić na osobnej stronie, niż dodać kolumny tak, jak należy, w bibliotece mediów. No jakoś nie potrafiłem znaleźć odpowiedniego rozwiązania.

Szukając na przemian „całowałem klamkę” nie znajdując nic, bądź byłem zalewany treściami wątpliwej jakości.

Cóż, udało mi się to znaleźć i teraz to sobie napiszemy. Chciałbym jednak zaznaczyć – jeżeli jest nam trudno się odnaleźć w tym wszystkim, gdy chcemy pisać coś własnego, to jest to jak najbardziej normalne, z powodów wymienionych powyżej.

Dobra, po pierwsze kolumna:

function column_id($columns) {
    $columns['colID'] = __('ID');
    return $columns;
} 
add_filter( 'manage_media_columns', 'column_id' );

Po drugie – niech ta kolumna zwraca ID naszych mediów:

function column_id_row($columnName, $ID){
    if($columnName == 'colID'){
       echo $ID;
    }
}
add_filter( 'manage_media_custom_column', 'column_id_row', 10, 2 );

Po trzecie – niech będzie sortowalna:

add_filter( 'manage_upload_sortable_columns', 'sortable_mediaid_column' );
function sortable_mediaid_column( $columns ) {
    $columns['colID'] = 'ID';
    return $columns;
}

Dlaczego ten hook nazywa się 'manage_upload_sortable_columns’ i jak to się ma do ogólnie przyjętej konwencji? Nie wiem. Pojęcia nie mam.

Ale działa.

Rest API – własny route

Jeżeli jeszcze o tym nie wiemy – WordPress posiada własne API serwujące różnego rodzaju treści w formacie JSON. Na przykład nasze posty możemy dostać w JSONie pod adresem:

http://localhost/blocktry2/wp-json/wp/v2/posts

Oczywiście pierwsza część adresu będzie inna. Ja to mam na localhoście w folderze blocktry2.

A gdybyśmy tak chcieli jeden post? Albo ograniczoną ilość?

http://localhost/blocktry2/wp-json/wp/v2/posts?per_page=1

CPT (custom post types) też są do znalezienia w rest API. Wystarczy, że przekażemy im przy tworzeniu argument 'show_in_rest’ ustawiony na wartość 'true’.

Natomiast mogą być sytuacje, w których chcemy napisać własny endpoint dla naszego API i to sobie teraz zrobimy. Na prostym przykładzie.

Aby taki endpoint uzyskać robimy co następuje:

function custom_api_init() {
    register_rest_route('custom/v1', '/dice', array(
        'methods' => 'GET',
        'callback' => 'custom_api_get_dice',
    ));
}
add_action('rest_api_init', 'custom_api_init');   

Ten kod oznacza, że nasz endpoint odwiedzamy standardową metodą GET (to ta, której używa domyślnie przeglądarka internetowa – ten post również czytasz za pomocą metody GET), endpoint będzie dostępny pod adresem:

http://localhost/blocktry2/wp-json/custom/v1/dice

Oczywiście musimy dodać funkcję callback, którą zdefiniowaliśmy jako 'custom_api_get_dice’. Na razie niech tak wygląda:

function custom_api_get_dice($request) {
    $data = array("msg" => "Hello world");
    return rest_ensure_response($data);
}   

Teraz po wejściu na nasz adres główny + '/wp-json/custom/v1/dice’ dostaniemy taką informację:

{
  "msg": "Hello world"
}

Na ile ładnie/brzydko się format JSON wyświetla to już zależy od przeglądarki internetowej oraz zainstalowanych rozszerzeń takich jak JSON formatter. Domyślnie będzie wyglądało brzydko.

Oczywiście te dane nie są dla ludzi, nie w takiej formie (przez przeglądarkę). One są po to, aby kodem (np. skryptem JS wykorzystującym AJAX) można je było zaciągnąć dynamicznie z JavaScript po stronie klienta.

Tym niemniej – nie chcemy dostać oczopląsu debugując nasze API i pisząc nasz kod. Na razie to nie wydaje się takim problemem – na razie.

Wystarczy wejść na '/wp-json/wp/v2/posts’ bez żadnych rozszerzeń formatujących i szybko przekonamy się, że ich potrzebujemy.

No dobra, a teraz dodajmy jakąś funkcjonalność do naszego API. Niech symuluje rzut kostką sześcienną:

function custom_api_get_dice($request) {
    $roll = random_int(1,6);
    $data = array("roll" => $roll);
    return rest_ensure_response($data);
}   

Gotowe.

Korzystanie z API, tworzenie pluginów z blokami – podstawy

Spróbujemy skorzystać sobie z naszego API, przy okazji ucząc się pisać pluginy z własnymi blokami. Najpierw sprawdźmy, w jakim folderze się znajdujemy. Jeżeli nie w plugins tylko jakimś podfolderze – przechodzimy do góry komendą change directory, aż się w plugins znajdziemy:

cd ..

Teraz używamy poniższej komendy, aby utworzyć plugin zawierający blok dynamiczny:

npx @wordpress/create-block@latest test-block-plugin --variant=dynamic

Po zainstalowaniu wszystkiego przechodzimy do folderu naszego pluginu komendą change directory:

cd test-block-plugin

Zarówno o bibliotece React jak i tworzeniu bloków pisałem już tutoriale dostępne na tej stronie, więc nie będę tutaj wszystkiego krok po kroku tłumaczyć.

W edit.js robimy importy:

import { useBlockProps } from '@wordpress/block-editor';
import apiFetch from '@wordpress/api-fetch';
import { useState, useEffect } from '@wordpress/element';

Teraz łączymy się z naszym API:

export default function Edit() {
	const apirequiest = async () => {
		const res = await apiFetch({ path: "custom/v1/dice" });
		console.log(res);
	  };
	  useEffect(() => {
		apirequiest();
	},[]);
	return (
			<div { ...useBlockProps() }>
				
			</div>
	);
}

Kompilujemy blok:

npm run build

Włączamy plugin, otwieramy dodawanie posta, dodajemy blok i patrzymy, co wylosowaliśmy w konsoli deweloperskiej. Ja akurat szczęścia nie miałem:

{roll: 1}

Możemy jeszcze sprawić, aby to nam się wyświetlało w elemencie, nie tylko konsoli:

export default function Edit() {
	const [roll, setRoll] = useState();
	const apirequiest = async () => {
		const res = await apiFetch({ path: "custom/v1/dice" });
		console.log(res);
		setRoll(res.roll);
	  };
	  useEffect(() => {
		apirequiest();
	},[]);
	return (
			<div { ...useBlockProps() }>
				<p>You rolled: {roll}</p>
			</div>
	);
}

Po wszystkim oczywiście blok trzeba ponownie skompilować.

A jak łączyć się z API nie z poziomu edycji ale poziomu zapisanego bloczka (widok posta, na którym mamy blok)?

Możemy wkleić to do pliku render.php:

<?php
/**
 * @see https://github.com/WordPress/gutenberg/blob/trunk/docs/reference-guides/block-api/block-metadata.md#render
 */
?>
<?php 
$api = file_get_contents('http://localhost/blocktry2/wp-json/custom/v1/dice');
$res = json_decode($api);
?>
<div <?php echo get_block_wrapper_attributes(); ?>>
	<p>You rolled: <?php echo $res->roll;?></p>
</div>

Jeżeli jesteśmy na localhoście i nie mamy zablokowane file_get_contents dla URLi, to jest to jakieś rozwiązanie.

Możemy też połączyć się z naszym API w bardziej WordPressowy sposób:

<?php 
$api = wp_remote_get('http://localhost/blocktry2/wp-json/custom/v1/dice');
$res = json_decode($api['body']);
?>
<div <?php echo get_block_wrapper_attributes(); ?>>
	<p>You rolled: <?php echo $res->roll;?></p>
</div>

Po wszystkim oczywiście:

npm run build