Piszemy dość praktyczny plugin, który pozwala nam wybrać obrazek i podejrzeć jego ID. Tworzymy blok dynamiczny oraz plugin z własną stroną dodaną w panelu admina, wyświetlającą obrazki oraz ich ID. Niezwykle przydatne, szybciej to napiszemy niż znajdziemy plugin do tego.

Przygotowanie naszego pluginu – standardowe, pierwsze kroki

Standardowo, przechodzimy do folderu wp-content, następnie do plugins w naszej instalacji WordPressa. Stworzymy tam sobie blok o nazwie media-id-inspector3 przy pomocy poniższej, już nam dobrze znanej komendy:

npx @wordpress/create-block@latest media-id-inspector-3 --variant="dynamic"

Gdy wszystko będzie gotowe, przechodzimy do naszego folderu przy pomocy komendy cd (change directory):

 cd media-id-inspector-3

Jako że nasz plugin będzie miał własną stronę w panelu admina to jeszcze nie wszystko, co musimy zrobić, aby przygotować nasz projekt. Zanim udamy się do folderu src musimy jeszcze dokonać pewnych zmian w pliku media-id-inspector-3.php – to plik główny naszego pluginu.

Poniżej tego, co generator nam automatycznie wygenerował dodajemy naszą stronę w panelu admina:

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

Strona ma tytuł i nazwę „Media ID”, wymaga uprawnień „manage options”, jej slug to „mediaID” zaś callback generujący jej zawartość to „mediaID_page_callback” (za chwilę tę funkcję sobie napiszemy). Funkcja podpięta do akcji „admin_menu” czyli tej wyświetlającej menu admina.

Teraz dodajemy ten kod z jakąś treścią:

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

Nasz plugin powinien wyglądać mniej więcej tak:

<?php
/**
 * Plugin Name:       Media Id Inspector 3
 * Description:       Example block scaffolded with Create Block tool.
 * Requires at least: 6.1
 * Requires PHP:      7.0
 * Version:           0.1.0
 * Author:            The WordPress Contributors
 * License:           GPL-2.0-or-later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       media-id-inspector-3
 *
 * @package CreateBlock
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Registers the block using the metadata loaded from the `block.json` file.
 * Behind the scenes, it registers also all assets so they can be enqueued
 * through the block editor in the corresponding context.
 *
 * @see https://developer.wordpress.org/reference/functions/register_block_type/
 */
function create_block_media_id_inspector_3_block_init() {
	register_block_type( __DIR__ . '/build' );
}
add_action( 'init', 'create_block_media_id_inspector_3_block_init' );

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 '</div>';
}

Możemy go teraz włączyć i sprawdzić, czy zakładka Media ID została dodana do panelu admina i czy wyświetla to, co sobie napisaliśmy.

Teraz możemy już przejść do pliku edit.js w folderze src i dodać tam potrzebne importy. Będzie to useBlockProps (standard) oraz MediaPlaceholder a także hook useState z biblioteki React:

import { useBlockProps, MediaPlaceholder } from '@wordpress/block-editor';
import { useState } from "react";

Możemy zaczynać!

Edit.js – podglądanie obrazków i ich ID podczas edytowania postów

Piszemy komponent czysto do używania wewnątrz panelu dodawania postów, aby podejrzeć sobie ID wybranego przez nas obrazka za pomocą komponentu MediaPlaceholder. Będzie on wyglądał tak:

export default function Edit() {
	return (
		<div { ...useBlockProps() }>
			<MediaPlaceholder
			icon="format-image"
			labels={{
				title: 'Wybierz obraz',
				instructions: 'Przeciągnij i upuść obraz lub kliknij, aby wybrać z biblioteki mediów.',
			}}
			onSelect={(media) => console.log(media.id)}
			accept="image/*"
			allowedTypes={['image']}
			/>
		</div>
	);
}

Jak widać, po wybraniu obrazka zostaje wykonany console.log z jego ID. Możemy to sobie sprawdzić w panelu edycji/dodawania posta, oczywiście plugin musi być włączony a po dokonanej zmianie musimy użyć komendy:

npm run build

Średnio wygodne to. Postarajmy się lepiej to zrobić – użyjmy Reactowego hooka useState:

export default function Edit() {
	const [id, setID] = useState("unknown");
	<h1>Image ID: {id}</h1>
	return (
		<div { ...useBlockProps() }>
			<MediaPlaceholder
			icon="format-image"
			labels={{
				title: 'Wybierz obraz',
				instructions: 'Przeciągnij i upuść obraz lub kliknij, aby wybrać z biblioteki mediów.',
			}}
			onSelect={(media) => setID(media.id)}
			accept="image/*"
			allowedTypes={['image']}
			/>
		</div>
	);
}

Reactowy hook useState przyjmuje argument z domyślną wartością oraz zwraca wartość i funkcję do jej ponownego ustawiania. Tutaj przyjął wartość domyślną „unknown” czyli „nieznany”. Wartość ta jest przypisana do naszego tagu <h1> i wyświetla się tam. MediaPlaceholder ma onSelect ustawiony tak, aby przy wybraniu obrazka ustawić „id” na id tego obrazka.

Możemy to sobie sprawdzić – najpierw mamy informację o tym, że ID nie jest znane. Po wybraniu obrazka otrzymujemy jego ID, wypisane już nie w konsoli ale wewnątrz naszego tagu <h1>.

Przydałby się jeszcze jakiś podgląd tego obrazka. Ponownie użyjemy useState:

export default function Edit() {
	const [id, setID] = useState("unknown");
	const [url, setUrl] = useState(null);
	function onSelectHanlder(media) {
		setID(media.id);
		setUrl(media.url);
	}
	return (
		<div { ...useBlockProps() }>
			<h1>Image ID: {id}</h1>
			<img src={url} />
			<MediaPlaceholder
			icon="format-image"
			labels={{
				title: 'Wybierz obraz',
				instructions: 'Przeciągnij i upuść obraz lub kliknij, aby wybrać z biblioteki mediów.',
			}}
			onSelect={(media) => onSelectHanlder(media)}
			accept="image/*"
			allowedTypes={['image']}
			/>
		</div>
	);
}

Tym razem już napisaliśmy sobie funkcję, która przyjmuje media i ustawia odpowiednie atrybuty. Mamy też tag <img> dla którego źródłem jest nasz url.

Można na tym poprzestać, aczkolwiek komponent MediaPlaceholder ma jeszcze jeden fajny atrybut, jakim jest mediaPreview. Korzystając z niego i prostego short-circuiting możemy napisać sobie taki zgrabny kod:

export default function Edit() {
	const [id, setID] = useState("unknown");
	const [url, setUrl] = useState(null);
	const mediaPreview = url && <img src={url}/>
	function onSelectHanlder(media) {
		setID(media.id);
		setUrl(media.url);
	}
	return (
		<div { ...useBlockProps() }>
			<h1>Image ID: {id}</h1>
			<MediaPlaceholder
			icon="format-image"
			labels={{
				title: 'Wybierz obraz',
				instructions: 'Przeciągnij i upuść obraz lub kliknij, aby wybrać z biblioteki mediów.',
			}}
			onSelect={(media) => onSelectHanlder(media)}
			accept="image/*"
			allowedTypes={['image']}
			mediaPreview={mediaPreview}
			/>
		</div>
	);
}

To już zależy od naszych preferencji. Tym niemniej – blok napisany. Rzecz jasna nadaje się tylko do edycji, sprawdzania, podglądania ID w edytorze postów.

Podglądaj ID mediów – strona naszego pluginu:

Na razie ta strona (w pliku głównym) wygląda tak:

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

Ciekawą rzeczą, która mogła nam umknąć, jest to, że różne media to tak naprawdę posty o typie „attachment”. Jeżeli zatem umiemy wynajdywać posty (typu 'post’ albo 'page’) to i z załącznikami nie powinniśmy mieć problemu:

function mediaID_page_callback() {
    echo '<div class="wrap">';
    echo '<h1>Media i ich ID</h1>';
	$args = array(
        'post_type'      => 'attachment',
        'post_mime_type' => 'image',
        'posts_per_page' => -1,
    );
    $images = get_posts($args);
    echo '</div>';
}

Bierzemy typ attachment, mime_type 'image’ i 'post_per_page’ ustawione na -1 czyli nieograniczona ilość. Te argumenty wrzucamy w funkcję get_posts i przypisujemy do zmiennej images. Teraz tylko potrzebna jest nam jakaś pętla, która przejdzie po wynikach i wszystko odpowiednio wypisze:

function mediaID_page_callback() {
    echo '<div class="wrap">';
    echo '<h1>Media i ich ID</h1>';
	$args = array(
        'post_type'      => 'attachment',
        'post_mime_type' => 'image',
        'posts_per_page' => -1,
    );
    $images = get_posts($args);
	echo '<ul>';
        foreach ($images as $image) {
            $image_id = $image->ID;
            $image_url = wp_get_attachment_url($image_id);
            echo '<li>';
            echo '<img src="' . esc_url($image_url) . '" alt="Image" width="100">';
            echo ' ID: ' . $image_id;
            echo '</li>';
        }
        echo '</ul>';
    echo '</div>';
}

Oczywiście warto byłoby się zabezpieczyć przed sytuacją, w której nie mamy żadnych mediów:

function mediaID_page_callback() {
    echo '<div class="wrap">';
    echo '<h1>Media i ich ID</h1>';
	$args = array(
        'post_type'      => 'attachment',
        'post_mime_type' => 'image',
        'posts_per_page' => -1,
    );
    $images = get_posts($args);
	if ($images) {
        echo '<ul>';
        foreach ($images as $image) {
            $image_id = $image->ID;
            $image_url = wp_get_attachment_url($image_id);
            echo '<li>';
            echo '<img src="' . esc_url($image_url) . '" alt="Image" width="100">';
            echo ' ID: ' . $image_id;
            echo '</li>';
        }
        echo '</ul>';
    } else {
        echo 'Brak obrazów w bibliotece mediów.';
    }
    echo '</div>';
}

Podaję teraz cały plik pluginu:

<?php
/**
 * Plugin Name:       Media Id Inspector 3
 * Description:       Example block scaffolded with Create Block tool.
 * Requires at least: 6.1
 * Requires PHP:      7.0
 * Version:           0.1.0
 * Author:            The WordPress Contributors
 * License:           GPL-2.0-or-later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       media-id-inspector-3
 *
 * @package CreateBlock
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Registers the block using the metadata loaded from the `block.json` file.
 * Behind the scenes, it registers also all assets so they can be enqueued
 * through the block editor in the corresponding context.
 *
 * @see https://developer.wordpress.org/reference/functions/register_block_type/
 */
function create_block_media_id_inspector_3_block_init() {
	register_block_type( __DIR__ . '/build' );
}
add_action( 'init', 'create_block_media_id_inspector_3_block_init' );

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>';
	$args = array(
        'post_type'      => 'attachment',
        'post_mime_type' => 'image',
        'posts_per_page' => -1,
    );
    $images = get_posts($args);
	if ($images) {
        echo '<ul>';
        foreach ($images as $image) {
            $image_id = $image->ID;
            $image_url = wp_get_attachment_url($image_id);
            echo '<li>';
            echo '<img src="' . esc_url($image_url) . '" alt="Image" width="100">';
            echo ' ID: ' . $image_id;
            echo '</li>';
        }
        echo '</ul>';
    } else {
        echo 'Brak obrazów w bibliotece mediów.';
    }
    echo '</div>';
}

W panelu admina możemy znaleźć zakładkę Media ID i przechodząc tam zobaczymy obrazki oraz ich ID ładnie wypisane. Dla uproszczenia podglądu uznałem, że dobrze będzie wyświetlać je z ograniczoną szerokością.

Oczywiście możemy ograniczyć ich wielkość w inny sposób, np. wybierając funkcję wp_get_attachment_image_url, która pozwala nam wybrać sobie rozmiar (niech to będzie 'thumbnail’ czyli najmniejszy):

function mediaID_page_callback() {
    echo '<div class="wrap">';
    echo '<h1>Media i ich ID</h1>';
	$args = array(
        'post_type'      => 'attachment',
        'post_mime_type' => 'image',
        'posts_per_page' => -1,
    );
    $images = get_posts($args);
	if ($images) {
        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.';
    }
    echo '</div>';
}

Blok w render.php – czy warto?

Skoro nasz blok służy do debugowania naszej strony, w tym wypadku podglądania naszych ID przypisanych obrazkom, to nie warto w ogóle tworzyć zawartości render.php – blok do debugowania nie służy do pokazywania użytkownikowi. Taki blok, dodany do posta, powinien zostać natychmiast usunięty po sprawdzeniu tego, co sprawdzić chcieliśmy.

Tym niemniej, myślę że ciekawym ćwiczeniem będzie przepisanie naszej funkcji callback do pliku render.php. Możemy to spróbować sobie zrobić samemu, jeżeli nie – oto kod:

<?php
/**
 * @see https://github.com/WordPress/gutenberg/blob/trunk/docs/reference-guides/block-api/block-metadata.md#render
 */
$args = array(
	'post_type'      => 'attachment',
	'post_mime_type' => 'image',
	'posts_per_page' => -1,
);
$images = get_posts($args);
?>
<div <?php echo get_block_wrapper_attributes(); ?>>

<?php 
   
    if ($images) {
        echo '<ul>';
        foreach ($images as $image) {
            $image_id = $image->ID;
            $image_url = wp_get_attachment_url($image_id);
            echo '<li>';
            echo '<img src="' . esc_url($image_url) . '" alt="Image" width="100">';
            echo ' ID: ' . $image_id;
            echo '</li>';
        }
        echo '</ul>';
    } else {
        echo 'Brak obrazów w bibliotece mediów.';
    }
	?>

</div>

Całe ćwiczenie polega na umiejętnym zastosowaniu otwierających i zamykających bloków PHP, używaniu echo z HTMLowym markupem oraz samego HTML poza PHP. Po tym komenda:

npm run build

Teraz możemy zapisać blok i na stronie zobaczyć listę mediów i ich ID. Coś, czego nie chcielibyśmy pokazywać użytkownikowi a w panelu admina mamy od tego zakładkę, do której trzeba mieć uprawnienia manage_options. Możemy zatem zawartość rendera usunąć i w ogóle nie zapisywać bloków służących do debugowania.

Tym niemniej – wykonaliśmy dzisiaj bardzo ciekawy mini-projekt.

Dodanie shortcode do naszego projektu

Kolejną ciekawą rzeczą, jaką możemy zrobić, jest dodanie shortcode do naszego projektu. Dodajmy sobie coś takiego w pliku głównym naszego pluginu, tuż pod rejestracją naszego bloku:

if ( ! shortcode_exists( 'media_ids' ) ) {
    function media_ids_shortcode() {
	
	}
    add_shortcode('media_ids', 'media_ids_shortcode');
  } 

Teraz wystarczy skopiować tam zawartość naszego callbacku od naszej strony Media 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) {
			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.';
		}
	}
    add_shortcode('media_ids', 'media_ids_shortcode');
  } 

Musimy dokonać pewnych zmian, bowiem shortcode musi coś zwracać, nie robić echo

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) {
			$output =  '<ul>';
			foreach ($images as $image) {
				$image_id = $image->ID;
				$imageUrl = wp_get_attachment_image_url($image_id, 'thumbnail');
				$output .= '<li>';
				$output .=  '<img src="' . esc_url($imageUrl) . '" alt="Image">';
				$output .=  ' ID: ' . $image_id;
				$output .=  '</li>';
			}
			$output .= '</ul>';
			return $output;
		} else {
			echo 'Brak obrazów w bibliotece mediów.';
		}
	}
    add_shortcode('media_ids', 'media_ids_shortcode');
  } 

Teraz tylko pozostaje nam dostosować naszą funkcję callback do użycia shortcode:

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

I już. To samo możemy uzyskać w plinku render.php, jeżeli bardzo chcemy:

<?php
/**
 * @see https://github.com/WordPress/gutenberg/blob/trunk/docs/reference-guides/block-api/block-metadata.md#render
 */
?>
<div <?php echo get_block_wrapper_attributes(); ?>>

	<?php echo do_shortcode('[media_ids]'); ?>
    
</div>

Możemy ten shortcode używać gdziekolwiek na stronie, we wpisach bądź z poziomu PHP. Warto jeszcze dodać, że jeżeli nie chcemy bawić się w „sklejanie” napisu tak, jak to pokazałem to nasz shortcode może wykorzystać mechanizm output buffering i zwrócić treść w ten sposób:

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');
  } 

To już zależy od naszych upodobań.