Iterate over objects (WP-CLI): verschil tussen versies

Uit De Vliegende Brigade
Naar navigatie springen Naar zoeken springen
(Nieuwe pagina aangemaakt met 'I feel perplexed that there seem to be no obvious way to be to iterate over a collection of objects, like posts or taxonomy terms. To add insult to injury: WP-CLI c...')
 
k (Jeroen Strompf heeft pagina Iterate over objects (WPI-CLI) hernoemd naar Iterate over objects (WP-CLI))
 
(13 tussenliggende versies door dezelfde gebruiker niet weergegeven)
Regel 1: Regel 1:
I feel perplexed that there seem to be no obvious way to be 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 max. 100 items at a time.
+
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.
  
Currently, this seems a quite good approach:
+
== 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:
  
 
<pre>
 
<pre>
Regel 13: Regel 15:
 
</pre>
 
</pre>
  
* I tend to rewrite the mapfile line to <code>mapfile -t j < <( wp db query "$i" --skip-column-names | grep . )</code>, but it doesn't seem necessary here.
+
* 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 <code>|grep .</code> to remove whitespace, like <code>mapfile -t j < <( wp db query "$i" --skip-column-names | grep . )</code>, but it doesn't seem necessary here
 
* <code>--skip-column-names</code> is a ''mysql Client option'' → https://dev.mysql.com/doc/refman/8.0/en/mysql-command-options.html
 
* <code>--skip-column-names</code> is a ''mysql Client option'' → https://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 (<code>tourlib-en-taxonomies-pa.sh</code> » <code>translate_pa_diagram_terms()</code>):
 +
 +
<pre>
 +
#
 +
# 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[@]}"
 +
</pre>
 +
 +
''' Second example '''
 +
 +
Only max. 100 ids are returned. This example below contains a loop, to make sure that all ids are collected (<code>tourlib-en-taxonomies-pa.sh</code> » <code>translate_pa_original_xxx_widget_terms)</code>)
 +
 +
<pre>
 +
# 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
 +
</pre>
 +
 +
* 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:
 +
 +
<pre>
 +
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
 +
</pre>
 +
 +
== See also ==
 +
 +
* [[Mapfile (Bash)]]
 +
* [[Pipelining & redirection (Bash)]]
 +
* [[Wp db query (WP-CLI)]]

Huidige versie van 14 nov 2022 om 20:31

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