Będziemy dodawać elementy wpisu z poziomu JavaScript w konsoli deweloperskiej (na stronie edycji/dodawania posta). Zabieramy się za temat ważny, który w dodatku nigdzie nie jest porządnie ani przystępnie dla początkujących opisany. Ci, który nauczyli się tego, mają to gdzieś (ewentualnie zrobili sobie cheatsheet, jeżeli jeszcze tego na pamięć nie znają) zaś inni mają po prostu problem.

Sprawdzamy ile bloków na stronie – skrypt

No to tworzymy/edytujemy wpis z edytorem Gutenberg (to ten, który nie wygląda, jakby został wyciągnięty z lat dziewięćdziesiątych, bo jest jeszcze inny, co dla przyzwoitości wspominam).

Teraz dodajmy sobie „plusikiem” kilka paragrafów oraz nagłówków. Gdy już to będziemy mieć, otwieramy konsolę w narzędziach deweloperskich i wklejamy ten kod:

wp.data.select('core/block-editor').getGlobalBlockCount();

Dostaniemy liczbę bloków obecnych na stronie. W zależności od przeglądarki możliwe, że będziemy musieli wrzucić to w console.log (w REPLu na Chromie nie ma takiej potrzeby).

Teraz policzmy sobie same nagłówki:

wp.data.select('core/block-editor').getGlobalBlockCount('core/heading');

Pokazuje nam, ile nagłówków mamy.

Napiszmy sobie funkcję, która wyloguje ile paragrafów mamy:

function log_paragraphs(){
	let num_of_para = wp.data.select('core/block-editor').getGlobalBlockCount('core/paragraph');
	console.log(num_of_para);
}

Tę funkcję trzeba wkleić do konsoli deweloperskiej, a następnie ją wywołać:

log_paragraphs();

Jeżeli korzystamy z Chrome to możemy darować sobie console.log, bo wartość zwracana jest w REPLu logowana:

function log_paragraphs(){
	let num_of_para = wp.data.select('core/block-editor').getGlobalBlockCount('core/paragraph');
	return num_of_para;
}

Pierwsze zabawy z core/block-editor mamy już za sobą.

Średnia ilość znaków w paragrafie – skrypt

Okej, postarajmy się „złapać” wszystkie paragrafy. Robimy to poniższą funkcją:

 wp.data.select('core/block-editor').getBlocksByName('core/paragraph');

W zamian dostajemy listę zawierającą ID tych paragrafów.

Do „łapania” paragrafu (czy innego bloczka) po jego ID służy funkcja getBlock:

wp.data.select('core/block-editor').getBlock(id)

Możemy teraz posklejać to do kupy i napisać funkcję, która złapie wszystkie ID paragrafów, zapisze ich ilość (taka sama jak ilość numerów ID) oraz wyloguje każdy paragraf:

function log_paragraphs(){
	let para_ids = wp.data.select('core/block-editor').getBlocksByName('core/paragraph');
	let num_of_paras = para_ids.length;
	para_ids.forEach((id) => {
		console.log(wp.data.select('core/block-editor').getBlock(id));
	});
}

Teraz warto zobaczyć wylogowane obiekty i postarać się odnaleźć ich zawartość oraz jej długość. Ja to widzę w 'attributes.content.length’:

function log_paragraphs(){
	let para_ids = wp.data.select('core/block-editor').getBlocksByName('core/paragraph');
	let num_of_paras = para_ids.length;
	para_ids.forEach((id) => {
		console.log(wp.data.select('core/block-editor').getBlock(id).attributes.content.length);
	});
}

Możemy zatem napisać funkcję, która wylicza nam średnią ilość znaków, jakie mamy w paragrafie:

function log_paragraphs(){
	let para_ids = wp.data.select('core/block-editor').getBlocksByName('core/paragraph');
	let num_of_paras = para_ids.length;
	let sum_of_chars = 0
	para_ids.forEach((id) => {
		sum_of_chars += wp.data.select('core/block-editor').getBlock(id).attributes.content.length;
	});
	return sum_of_chars/num_of_paras;
}

Pamiętajmy tylko, aby po wklejeniu definicji funkcji, wkleić jej wywołanie:

log_paragraphs();

Dlaczego nie wkleić obu na raz? Cóż, REPL może się trochę przywiesić i po prostu lepiej to kawałkami wklejać. Jeżeli wkleimy funkcję i jej wywołanie jednym fragmentem kodu, to przeglądarka może nie zdążyć ten funkcji zapisać.

Po co nam tablica z numerami ID skoro później trzeba wywołać getBlock?

Obserwując naszą funkcję takie pytanie sobie możemy zadać. Cóż, istnieje wiele funkcji dispatch, które jako argument przyjmują ID bloczka, a potrafią zrobić naprawdę wiele.

Dodajmy kilka nagłówków, o różnej wielkości (h2, h4, h6). Teraz pora na kod, który złapie wszystkie ID po nazwie i przejdzie po nich, robiąc update na atrybucie 'level’, sprowadzając je wszystkie do poziomu h2:

var headings = wp.data.select('core/block-editor').getBlocksByName('core/heading');
headings.forEach((heading) => {
	wp.data.dispatch( 'core/block-editor' ).updateBlock( heading, {
		attributes: {
		   level:2
		}
	}
	);
});

Użyłem var, bo pewnie jeszcze kilka razy to sobie w konsoli wkleimy. Jak widać wp.data.dispatch(’core/block’) posiada funkcję updateBlock, która przyjmuje ID oraz obiekt z naszym update.

Jako że pracujemy na atrybutach, możemy to sobie uprościć funkcją updateBlockAttributes:

var headings = wp.data.select('core/block-editor').getBlocksByName('core/heading');
headings.forEach((heading) => {
	wp.data.dispatch( 'core/block-editor' ).updateBlockAttributes( heading, {level:2});
});

Możemy teraz napisać sobie skrypt, który przeleci po wszystkich nagłówkach i sprawdzi, czy są takie, które nie mają kotwicy HTML (skrypt przydatny do spisów treści wszelkiego rodzaju):

function log_headings_no_anchor(){
	let headings = wp.data.select('core/block-editor').getBlocksByName('core/heading');
	let no_anchor_headings = [];
	let no_anchor_sum = 0;
	headings.forEach((heading_id) => {
		let heading = wp.data.select('core/block-editor').getBlock(heading_id);
		if(heading.attributes.anchor === undefined){
			no_anchor_headings.push(heading_id);
			no_anchor_sum += 1;
		}
	});
	console.log(`Heading without anchor ${no_anchor_sum}`);
	return no_anchor_headings;
}

Loguje ilość nagłówków pozbawionych kotwicy i jeszcze zwraca listę ich ID.

Tworzenie bloków w edytorze z poziomu skryptu

Tworzenie bloków w edytorze z poziomu skryptu trudne nie jest. Spróbujmy coś takiego:

const para = wp.blocks.createBlock( 
  'core/paragraph', { content: 'Hello World!' }
 );
wp.data.dispatch( 'core/block-editor' ).insertBlocks( para );

Podobnie ma się sprawa z innymi atrybutami. W ten sposób na przykład stworzymy sobie heading h3:

let h3 = wp.blocks.createBlock( 
	'core/heading', { content: 'Hello World!', level: 3 }
   );
wp.data.dispatch( 'core/block-editor' ).insertBlocks( h3 );

Napiszmy coś praktycznego, szczególnie jeżeli bawimy się w programowanie WordPressa i chcemy trochę „dummy contentu” do wypróbowania:

function generateLorem(num = 1) {
	const lorem = "Lorem ipsum dolor sit amet consectetur adipisicing elit. Quam, atque. Unde, tempora dignissimos? Corrupti, saepe amet ipsum voluptates, earum placeat quibusdam sed eum harum id rerum provident possimus rem molestias.";
	while(num) {
		let para = wp.blocks.createBlock( 
			'core/paragraph', { content: lorem }
		   );
		wp.data.dispatch( 'core/block-editor' ).insertBlocks( para );
	num--;
	}
}

Ten kod generuje paragrafy z „lorem ipsum”. Domyślnie – jeden, możemy jednak przekazać większą ilość:

generateLorem(3);

Łapiemy zaznaczony blok z poziomu skryptu

Musimy skupić się na jakimś bloku, a następnie wyjść do konsoli deweloperskiej, nie tracąc focusa, i wkleić to:

wp.data.select('core/block-editor').getSelectedBlock();

Możemy też złapać ID naszego bloczka:

wp.data.select('core/block-editor').getSelectedBlock().clientId;

Jeżeli potrzebujemy tylko ID, mamy od tego specjalną funkcję:

wp.data.select('core/block-editor').getSelectedBlockClientId();

Teraz coś praktycznego, co przyda się do komponentu z fragmentem kodu (albo czymkolwiek, co chcemy wyposażyć w przycisk kopiuj). Piszemy kod, który pozwoli nam skopiować do schowka zawartość nagłówka/paragrafu.

Od razu zwracam uwagę – w przypadku jednego content jest obiektem, zaś tekst znajduje się w atrybucie text, w przypadku drugiego content zawiera tekst.

Na początku wylogujmy nasz tekst. Pamiętajmy tylko o tym, że musimy mieć skupienie (na paragraf/nagłówek), nie traćmy go wychodząc do konsoli:

function copyContentToClipboard() {
	let block = wp.data.select('core/block-editor').getSelectedBlock();
	let content = block.attributes.content instanceof Object ? block.attributes.content.text : block.attributes.content;
	console.log(content);
  }

Teraz jeszcze tylko wywołanie:

copyContentToClipboard()

Powinno wylogować nam zawartość tekstową. Teraz możemy ją skopiować do schowka:

function copyContentToClipboard() {
	let block = wp.data.select('core/block-editor').getSelectedBlock();
	let content = block.attributes.content instanceof Object ? block.attributes.content.text : block.attributes.content;
	navigator.clipboard.writeText(content)
	  .then(() => {
		console.log('Text copied to clipboard');
	  })
	  .catch(err => {
		console.error('Failed to copy text: ', err);
	  });
  }

Wklejamy nową wersję funkcji do konsoli, ale jeszcze nie wywołujemy. Navigator działa w ten sposób, że nie skopiuje nam tekstu, jeżeli nie będziemy mieli focusa na stronie. Nawet bycie w konsoli nie wystarcza (ma to sens, czemu jakaś zminimalizowana karta ma mieć dostęp do naszego schowka i na przykład zapychać go niechcianą zawartością?).

A zatem nasze wywołanie wygląda tak:

 setTimeout(() => {
	copyContentToClipboard();
  }, 3000);

Mamy wtedy 3 sekundy, aby kliknąć element, który ma być skopiowany. Focus musi być na elemencie, ale też ogólny focus na dokumencie, nie konsoli.

Oczywiście jak będziemy pisać komponent, korzystający z guzika kopiuj to się tym nie będziemy przejmować, ale teraz tylko ćwiczymy w konsoli, więc takie przygody mamy.

Kod skopiuje zawartość, tak paragrafu jak i nagłówka.

Łapanie aktualnie zaznaczonego tekstu z poziomu skrypty

Nie chcę się tu niepotrzebnie zagłębiać w temat i robić przydługi cheatsheet – zrobiliśmy kawał ćwiczeń, dzięki którym będziemy w stanie pisać dynamiczne i ciekawe bloki i resztę materiału poznamy „w locie”, znając już podstawy.

Tym niemniej, zaznaczmy sobie jakiś tekst w bloku i wrzućmy ten kod w konsolę:

wp.data.select('core/block-editor').getSelectionStart().offset

Wypisze nam indeks początkowy zaznaczonego tekstu. Teraz ten kod:

wp.data.select('core/block-editor').getSelectionEnd().offset

To indeks końcowy. Taka mała, sprytna funkcja wyloguje nam ilość zaznaczonych znaków:

function selected_chars(){
	let start = wp.data.select('core/block-editor').getSelectionStart().offset;
	let end = wp.data.select('core/block-editor').getSelectionEnd().offset;
	return Math.abs(start - end);
  }

Wystarczy tylko zaznaczyć, wejść do konsoli i wywołać selected chars (wcześniej wklejając definicję funkcji oczywiście).