Skip to content

Instantly share code, notes, and snippets.

@johnalarcon
Created September 29, 2020 06:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnalarcon/8fd8626027d34748b066d1b532c50341 to your computer and use it in GitHub Desktop.
Save johnalarcon/8fd8626027d34748b066d1b532c50341 to your computer and use it in GitHub Desktop.
Extract full plugin details from README.md in a typical ClassicPress plugin.
<?php
namespace CodePotent\Readme2Complete;
// Usage
$readme_file = 'https://gist.githubusercontent.com/johnalarcon/c19d3111dc73578a3fe224084e2194ec/raw/9a9facfc849e915851fd99cbb6495ded9904340a/README.md';
$readme_lines = file($readme_file);
$readme_array = parse_readme($readme_lines);
// Result
echo '<h3>Extract Details from README.md</h3>';
echo '<p><strong>Source</strong>: <a href="'.$readme_file.'">'.$readme_file.'</a></p>';
echo '<p><strong>Result</strong>:</p>';
echo '<pre>';
print_r($readme_array);
echo '</pre>';
/**
* Get headers whitelist
*
* This function returns an array used for finding and whitelisting the many
* fields that might be found in a plugin's header.
*
*/
function get_header_whitelist() {
return [
'name:',
'description:',
'version:',
'text domain:',
'domain path:',
'requires php:',
'requires:',
'tested:',
'author:',
'author uri:',
'plugin uri:',
'download link:',
'theme uri:',
'donate link:',
'license:',
'license uri:',
'tags:',
];
}
/**
* Get sections whitelist
*
* This function returns an array used for finding and whitelisting a select
* number of the sections that may be present in a plugin's README.md file.
*
*/
function get_section_whitelist() {
return [
'description' => 'description',
'faq' => 'frequently asked questions',
'installation' => 'installation',
'screenshots' => 'screenshots',
'reviews' => 'reviews',
'other_notes' => 'other notes',
'changelog' => 'changelog',
'upgrade_notice' => 'upgrade notice',
];
}
/**
* Get header data.
*
* This function extracts many values from the header section of a README.md
* file as it would be wri
* the most common values from the header section of values that are often present in
* found in a plugin.
* in a CLassicPress plugin
* header section. The data is coming in as an array of lines.
*
* @param array $lines Scalar array of lines read from file.
*
* @return array The data from the endpoint's header section.
*
*/
function get_header(&$lines) {
// Initialize return variable.
$header = [];
// Line, please?!
foreach ($lines as $k=>$line) {
// Trim up the right side.
$line = rtrim($line);
// Assign trimmed value back to orginal array.
$lines[$k] = $line;
// Grab the plugin name: === Plugin Name ===
if (strpos(strtolower($line), '===') === 0) {
// Remove === and spaces; then unset from original array.
$header['name'] = trim(str_replace('===', '', $line));
unset($lines[$k]);
}
// Other values to check for in the header; lowercase; with colon.
$header_properties = get_header_whitelist();
// Iterate over $header_properties to check if they are in $line.
foreach ($header_properties as $str) {
// If $line is relevant, capture as k/v pair; unset from original array.
$key = str_replace(' ', '_', substr($str, 0, strlen($str)-1));
$value = trim(substr($line, strlen($str)));
if (strpos(strtolower($line), $str) === 0) {
$header[$key] = $value;
unset($lines[$k]);
}
}
} // foreach $lines
// Return the now-arrayed, header properties.
return $header;
}
/**
* Get data for whitelisted sections
*
*
*
* @param array $lines
* @return array[][]
*/
function get_sections(&$lines) {
// Particular sections of interest.
$natural_sections = get_section_whitelist();
// Throw my thing down, flip it, and reverse it. ~ Missy Elliot
$inverse_sections = array_flip($natural_sections);
// Initialization.
$sections = [];
// Flag.
$started = false;
// Iterate over lines.
foreach ($lines as $line) {
// Check flag; skip everything until a section is reached.
if (!$started && strpos($line, '==') !== 0) {
continue;
}
// Capture headings.
if (strpos($line, '==') === 0) {
// Ok, we're started...raise the flag!
$started = true;
// Capture the heading.
$heading = trim(str_replace('==', '', strtolower($line)));
// Capture only the whitelisted headings.
if (!empty($inverse_sections[$heading])) {
$sections[$inverse_sections[$heading]] = []; // Nope, remove it.
} else {
$sections[$heading][] = $heading; // Yep, whitelisted.
}
// The line was a heading; no need to go further; continue.
continue;
}
/**
* If here, the line is part of the last-found $heading array and should
* be stored as $sections[$heading][]
*/
if (!empty($inverse_sections[$heading])) {
$sections[$inverse_sections[$heading]][] = $line;
} else {
$sections[$heading][] = $line;
}
}
// Remove any unexpected sections.
foreach (array_keys($sections) as $heading) {
if (empty($natural_sections[$heading])) {
unset($sections[$heading]);
}
}
// Return the sections data.
return $sections;
}
/**
* Parse file into data array.
*
* @param array $lines Scalar array of lines from a README.md file.
*
* @return array[][] Array representing sections and lines in the file.
*
*/
function parse_readme($lines) {
// Initialize the return variable.
$data = [];
// Extract header data; alters $lines; passed by reference.
$header = get_header($lines);
// Extract sectional data; alters $lines; passed by reference.
$sections = get_sections($lines);
// NOT IN README. Unique identifier; ie, my-plugin-dir/my-plugin-file.php
$data['identifier'] = '';
// NOT IN README. Plugin directory name.
$data['slug'] = dirname($data['identifier']);
// Display name for the plugin.
$data['name'] = !empty($header['name']) ? $header['name'] : '';
// Plugin short description.
$data['description'] = !empty($sections['description']) ? $sections['description'] : '';
// Plugin version; ie, 1.2.3
$data['version'] = !empty($header['version']) ? $header['version'] : '';
// Text domain; ie, my-plugin-name
$data['text_domain'] = !empty($header['text_domain']) ? $header['text_domain'] : '';
// Text domain path; ie, /languages
$data['domain_path'] = !empty($header['domain_path']) ? $header['domain_path'] : '';
// Minimum PHP requirement; ie, 5.6, or 7, or 7.2, etc
$data['requires_php'] = !empty($header['requires_php']) ? $header['requires_php'] : '';
// Minimum ClassicPress requirement; ie, 1.1.1
$data['requires'] = !empty($header['requires']) ? $header['requires'] : '';
// Maximum ClassicPress compatibility; ie, 1.1.1
$data['tested'] = !empty($header['tested']) ? $header['tested'] : '';
// Author URL string.
$data['author'] = '';
if (!empty($header['author_uri']) && !empty($header['author'])) {
$data['author'] = '<a href="'.$header['author_uri'].'">'.$header['author'].'</a>';
}
// Author URL.
$data['author_uri'] = !empty($header['author_uri']) ? $header['author_uri'] : '';
// Plugin home page URI.
$data['plugin_uri'] = !empty($header['plugin_uri']) ? $header['plugin_uri'] : '';
// Direct link to download file.
$data['download_link'] = !empty($header['download_link']) ? $header['download_link'] : '';
// Donation link; ie, https://pay.me/?now-would-be-nice
$data['donate_link'] = !empty($header['donate_link']) ? $header['donate_link'] : '';
// License; ie, GPL v2
$data['license'] = !empty($header['license']) ? $header['license'] : '';
// License URL; ie, https://somesite.com/licence.html
$data['license_uri'] = !empty($header['license_uri']) ? $header['license_uri'] : '';
// NOT IN README. Last update; ie, 2019-12-16 15:02:08
$data['last_updated'] = '';
// NOT IN README. Release date; ie, 2019-12-16 15:02:08
$data['added'] = '';
// Since the sections array is bigger, put it at the end.
$data['sections'] = $sections;
// And that's a wrap!
return $data;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment