How to count rows of table in the_content()

Based on what you mentioned in the comments, I threw out the original answer.

If what you want to do is count the rows of a table contained in the post content, then all you really are doing is counting the <tr> tags to get the rows (assuming that all <tr> tags are to be counted). All other HTML tags can be ignored.

To do that, I would hook to template_redirect – it’s a late enough action that the $post object is available but early enough to give you flexibility on displaying the result somewhere in your post/page.

Counting can be done with substr_count() which gives you the number of occurrences of a string. Counting the <tr> tags then gives you the number of rows. (Note: count tags by the string “” in case the tags contain attributes.) The post content is available in $post->post-content.

This is placed in a global variable that is picked up in the custom display_table_row_count() you can use to display your result.

add_action( 'template_redirect', 'my_post_table_row_count' );
function my_post_table_row_count() {
    global $post, $table_rows_total;
    if ( is_single() && is_object( $post ) ) {
        // Count "<tr" instead of "<tr>" in case there are attributes
        $table_rows_total = substr_count( $post->post_content, '<tr' );
    } else {
        $table_rows_total = false;
    }
}

function display_table_row_count() {
    global $table_rows_total;
    return ( $table_rows_total ) ? $table_rows_total : '0';
}

Then wherever you need the result, you can use the following:

<?php echo display_table_row_count(); ?>

UPDATE to Address Questions in the Comments

To reflect additional requirements mentioned in the comments, the following is an edit of the code to be able to:

  1. Get a row count
  2. Get a count of specific string (see notes below for criteria)
  3. Work wherever it is needed (single.php, archive, etc)

For #3, since this would be called on archives as well, getting rid of the is_single() check is necessary. Otherwise it would only be available on single.php. If that’s not necessary, and this will be used on archives, then actually the utility function does not need to be hooked to template_redirect – or any other hook for that matter. It should be free to be called anywhere.

If it’s free to call anywhere though, keep in mind that the $post object will be whatever $post is being handled. So if it’s an archive loop, your function call will need to be in context of the Loop. If called outside the Loop, it will return just the $post that it is on (example: before the Loop it would return just the first post in the Loop).

For #2, there is a limitation to what I’ve provided here. This just searches for the count of occurrences of the requested string. That is working under the assumption that any row with the requested string only has a single occurrence of that that string in the row, thus giving a count of rows that have the string. If that string occurs more than once in a single row, it will not return an accurate result.

IF there would be situations where that occurs (string more than once in the row), the way to handle that would need to be different (and thus more complex) because you’d (probably) need to get an array of the rows, loop through that array, and count each row that has any occurrence of the requested string. That could be done, but not accurately with the information provided. So I limited this to the more probable situation of a single occurrence of the string in each row.

All you need is this utility:

function my_row_count( $search_for = false ) {
    // Get the $post object
    global $post;

    // If no "search_for" param, return the row count.
    if ( ! $search_for ) {
        return substr_count( $post->post_content, '<tr' );
    }

    // Get count for requested string
    $requested = substr_count( $post->post_content, $search_for );

    return ( $requested > 0 ) ? $requested : 0;
}

To display the total row count:

<?php echo my_row_count(); ?>

To display the count of a requested string (i.e. #123):

<?php echo my_row_count( '#123' ); ?>

Remember, if used on a page that is not a single post, the function must be used within the Loop.