Add valid XHTML closing img tags to WordPress galleries

As linked to from the comments on your question, the post_gallery filter should help you here.

Unlike a lot of other hooks though, you can’t filter the output that comes through from WordPress; you can only provide your own alternative output. This is slightly annoying, and results in you needing to build the gallery from scratch. You can do that with a bit of extra code, though, and the linked StackOverflow answer provides an example (but strangely uses <div src>, so just change that to <img src> – and then draw from the default WordPress markup for the rest, making sure to close your <img /> tag).


An alternative, where you can filter the output, is to use the the_content filter and some clever regex’ing. You need to be careful, because if you don’t think of all potential cases, your regex could catch something you don’t intend it to. This is exactly the problem the plugin author in this case is trying to avoid.

With that said, here’s a potential solution. Modify to your needs, but don’t rely on this as a 100% foolproof solution.

// priority must be more than 10, so it runs after the gallery shortcode does
add_filter( 'the_content', 'wpse231040_close_gallery_img_tags', 11);

  function wpse231040_close_gallery_img_tags ( $html ) {
    if ( strpos ( $html, '#gallery-' ) === false ) { return $html; }
    // make sure there's at least one gallery before running the more expensive preg_replace

    $html = preg_replace(
      '/
        (
          \<dl.*?class=["\'].*?gallery-item[\s"\'].*?   # look inside a <dl> with gallery-item class
          \<dt.*?class=["\'].*?gallery-icon[\s"\'].*?   # look inside a <dt> with gallery-icon class
          \<img\s                                       # look inside an <img> tag
        )
        (.*?)\>                                         # match the attributes inside the tag
      /sx',
      '$1$2 />',    // add the initial content, the img tag attributes, and finally a closing />
      $html
    );

  return $html;
  }