Making WordPress.org

Changeset 3827


Ignore:
Timestamp:
08/18/2016 12:12:09 PM (9 years ago)
Author:
dd32
Message:

Plugin Directory: Readme parsing: When parsing the FAQ section, pull out any properly formatted (and some not-so-well-formatted) Question & Answer pairs to be displayed in a formatted fashion.

The primary method we support for FAQ entries is where the sub headings are the question, with the content following as the answer. Both = and # are supported for this:

=== FAQ ===
== Does the plugin do X? ==
Yes!
## What about Y?
Nah, Sorry!

As plugins have a wide range of contents at present, we also support plugins which have used bolded headingslike the following, note, that it must start and end the line with two asterisks.
This format isn't suggested for future usage, and is only included for the thousand or more common plugins which have used it.

=== FAQ ===
** Can I contribute to the plugin? **
Yes! Patches Welcome!

Finally, there's the plugin readme's who don't confirm to any of the above standards, or have included a paragraph of data prior to their Q&A's, for those plugins the freeform content will be prepended to the FAQ section and they won't get a properly formatted accordian-style interface.

Props obenland for the initial patch, a lot of subtle changes have been made to better handle the various readme's out there (and probably more tweaks are needed).

See #1810

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/readme/class-parser.php

    r3553 r3827  
    6666     */
    6767    public $screenshots = array();
     68
     69    /**
     70     * @var array
     71     */
     72    public $faq = array();
    6873
    6974    /**
     
    287292        // Parse out the Upgrade Notice section into it's own data.
    288293        if ( isset( $this->sections['upgrade_notice'] ) ) {
    289             $lines   = explode( "\n", $this->sections['upgrade_notice'] );
    290             $version = null;
    291             $current = '';
    292             while ( ( $line = array_shift( $lines ) ) !== null ) {
    293                 $trimmed = trim( $line );
    294                 if ( empty( $trimmed ) ) {
    295                     continue;
    296                 }
    297 
    298                 if ( '=' === $trimmed[0] || '#' === $trimmed[0] ) {
    299                     if ( ! empty( $current ) ) {
    300                         $this->upgrade_notice[ $version ] = $this->sanitize_text( trim( $current ) );
    301                     }
    302 
    303                     $current = '';
    304                     $version = trim( $line, "#= \t" );
    305                     continue;
    306                 }
    307 
    308                 $current .= $line . "\n";
    309             }
    310             if ( ! empty( $version ) && ! empty( $current ) ) {
    311                 $this->upgrade_notice[ $version ] = $this->sanitize_text( trim( $current ) );
    312             }
     294            $this->upgrade_notice = $this->parse_section( $this->sections['upgrade_notice'] );
     295            $this->upgrade_notice = array_map( array( $this, 'sanitize_text' ), $this->upgrade_notice );
    313296            unset( $this->sections['upgrade_notice'] );
     297        }
     298
     299        // Display FAQs as a definition list.
     300        if ( isset( $this->sections['faq'] ) ) {
     301            $this->faq = $this->parse_section( $this->sections['faq'] );
     302            $this->sections['faq'] = '';
    314303        }
    315304
     
    317306        $this->sections       = array_map( array( $this, 'parse_markdown' ), $this->sections );
    318307        $this->upgrade_notice = array_map( array( $this, 'parse_markdown' ), $this->upgrade_notice );
     308        $this->faq            = array_map( array( $this, 'parse_markdown' ), $this->faq );
    319309
    320310        // Sanitize and trim the short_description to match requirements.
     
    333323            }
    334324            unset( $this->sections['screenshots'] );
     325        }
     326
     327        if ( ! empty( $this->faq ) ) {
     328            // If the FAQ contained data we couldn't parse, we'll treat it as freeform and display it before any questions which are found.
     329            if ( isset( $this->faq[''] ) ) {
     330                $this->sections['faq'] .= $this->faq[''];
     331                unset( $this->faq[''] );
     332            }
     333
     334            if ( $this->faq ) {
     335                $this->sections['faq'] .= "\n<dl>\n";
     336                foreach ( $this->faq as $question => $answer ) {
     337                    $this->sections['faq'] .= "<dt>{$question}</dt>\n<dd>{$answer}</dd>\n";
     338                }
     339                $this->sections['faq'] .= "\n</dl>\n";
     340            }
    335341        }
    336342
     
    414420            'ul'         => true,
    415421            'ol'         => true,
     422            'dl'         => true,
     423            'dt'         => true,
     424            'dd'         => true,
    416425            'li'         => true,
    417426            'h3'         => true,
     
    496505
    497506    /**
     507     * Parses a slice of lines from the file into an array of Heading => Content.
     508     *
     509     * We assume that every heading encountered is a new item, and not a sub heading.
     510     * We support headings which are either `= Heading`, `# Heading` or `** Heading`.
     511     *
     512     * @param string|array $lines The lines of the section to parse.
     513     * @return array
     514     */
     515    protected function parse_section( $lines ) {
     516        $key = $value = '';
     517        $return = array();
     518
     519        if ( ! is_array( $lines ) ) {
     520            $lines = explode( "\n", $lines );
     521        }
     522
     523        while ( ( $line = array_shift( $lines ) ) !== null ) {
     524            $trimmed = trim( $line );
     525            if ( ! $trimmed ) {
     526                $value .= "\n";
     527                continue;
     528            }
     529
     530            // Normal headings (##.. == ... ==) are matched if they exist, Bold is only used if it starts and ends the line.
     531            if ( $trimmed[0] == '#' || $trimmed[0] == '=' || ( substr( $trimmed, 0, 2 ) == '**' && substr( $trimmed, -2 ) == '**' ) ) {
     532                if ( $value ) {
     533                    $return[ $key ] = trim( $value );
     534                }
     535
     536                $value = '';
     537                // Trim off the first character of the line, as we know that's the heading style we're expecting to remove.
     538                $key   = trim( $line, $trimmed[0] . " \t" );
     539                continue;
     540            }
     541
     542            $value .= $line . "\n";
     543        }
     544
     545        if ( $key || $value ) {
     546            $return[ $key ] = trim( $value );
     547        }
     548
     549        return $return;
     550    }
     551
     552    /**
    498553     * @param string $text
    499554     * @return string
Note: See TracChangeset for help on using the changeset viewer.