Iterate over objects (WP-CLI)

Uit De Vliegende Brigade
Versie door Jeroen Strompf (overleg | bijdragen) op 14 nov 2022 om 20:31 (Jeroen Strompf heeft pagina Iterate over objects (WPI-CLI) hernoemd naar Iterate over objects (WP-CLI))
(wijz) ← Oudere versie | Huidige versie (wijz) | Nieuwere versie → (wijz)
Naar navigatie springen Naar zoeken springen

There seems to be no obvious way to iterate over a collection of objects, like posts or taxonomy terms. To add insult to injury: WP-CLI commands that return object-IDs, are often limited to returning max. 100 ids at a time.

Hybrid SQL-WP-CLI solution

As of Nov. 2022, this seems a quite good approach. In this example, the ids are collected of the terms of a certain WooCommerce product attribute taxonomy:

i='select term_id from wp_terms join wp_term_taxonomy using (term_id) where taxonomy like "pa_as%"'
mapfile -t j < <( wp db query "$i" --skip-column-names )

echo ${j[@]}
echo "# of entries: ${#j[@]}"
echo ${!j[@]}
echo "Entry 5: ${j[5]}"
  • It's only two lines of Bash code (the last four lines are debugging)
  • It's so simple that I don't even see the point of turning this into a function to be incorporated in some general WP-CLI-Bash library
  • All IDs are received at once: No need for iterations. And thanks to SQL, it's already vector-oriented
  • Much faster than using a 100% WP-CLI approach
  • I tend to extend these kind of mapfile lines with a filter |grep . to remove whitespace, like mapfile -t j < <( wp db query "$i" --skip-column-names | grep . ), but it doesn't seem necessary here
  • --skip-column-names is a mysql Client optionhttps://dev.mysql.com/doc/refman/8.0/en/mysql-command-options.html
  • I feel ok with using SQL for this, rather than going through the WP-CLI interface: Use what works.

100% WP-CLI solution

First example

Example from Oct. 2022 (tourlib-en-taxonomies-pa.sh » translate_pa_diagram_terms()):

#
# Store all term ids in array "termid"
########################################
#
# * All fields: wp --user=4 wc product_attribute_term list 20
# * Only ids:  wp --user=4 wc product_attribute_term list 20 --field=id
# * Use "grep ." to remove some whitespace
# * Max. 100 items are returned at a time. There are 149 items in total,
#   so just merge the input of 2x this command
#
taxid=20	# Taxonomy-IDA more extensive example: 
#
mapfile -t j0 < <( wp --user=4 wc product_attribute_term list $taxid --field=id | grep . )
mapfile -t j1 < <( wp --user=4 wc product_attribute_term list $taxid --field=id --offset=100 | grep . )
termid=( "${j0[@]}" "${j1[@]}" )
#
echo "Length of array j0: ${#j0[@]}"
echo "Length of array j1: ${#j1[@]}"
echo "Length of array termid:  ${#termid[@]}"
echo "Array termid: ${termid[@]}"

Second example

Only max. 100 ids are returned. This example below contains a loop, to make sure that all ids are collected (tourlib-en-taxonomies-pa.sh » translate_pa_original_xxx_widget_terms))

# Assign taxonomy id
########################################
#
taxonomy_id=23
#
echo "Init:"
echo "	taxonomy_id: $taxonomy_id"


# Store number of terms in term_id_rows
########################################
#
#
term_id_rows=$(wp --user=4 wc product_attribute_term list $taxonomy_id --format=count | grep .)
echo "	term_id_rows: $term_id_rows"


# Calculate number of iterations
########################################
#
number_of_iterations=$(($term_id_rows/100+1))
echo "	number_of_iterations: $number_of_iterations"


# Unset term_id array
########################################
#
# This array will contain all term ids
#
unset term_id


# Collect all term_ids - Loop through all terms
########################################
#
i=1
echo "Loop - Collect all term_ids"
#
for ((i; i<=$number_of_iterations; i++))	
do
	#
	echo "	Iteration $i/$number_of_iterations"
	#
	# Store batch of term ids in tmp array j
	########################################
	#
	mapfile -t j < <( wp wc product_attribute_term list \
		$taxonomy_id \
		--user=4 \
		--field=id \
		--offset=$((($i-1)*100)) | grep . )
	#
	# echo "	j: ${j[@]}"
	#
	# Append to array term_id
	########################################
	#
	term_id=(${term_id[@]} ${j[@]})
	echo "		Length term_id: ${#term_id[@]}"
	#
done
  • Of course, this code can be made more compactly
  • If I remember correctly, execution took about half a minute. That became quite annoying, since this code is only 'preparatory': The real action comes after this. When I have to wait for half a minute, every time before I get to debug the real code, that becomes quite tiring.

Same functionality, but more compact:

term_id_rows=$(wp --user=4 wc product_attribute_term list 23 --format=count | grep .)
number_of_iterations=$(($term_id_rows/100+1))
i=1
for ((i; i<=$number_of_iterations; i++))	
do
   mapfile -t j < <( wp wc product_attribute_term list \
      $taxonomy_id --user=4 --field=id \
      --offset=$((($i-1)*100)) | grep . )
   term_id=(${term_id[@]} ${j[@]})
done

See also