Skip to content

Commit 376b42c

Browse files
authored
Prefer path-based plugin slug over text domain (#12)
Change slug resolution to prefer the plugin directory name, then the plugin file name, and only then fall back to the header text_domain. Added unit tests covering directory/file/text-domain precedence and helper methods to create/remove temporary plugin directories for these tests.
1 parent b77c55e commit 376b42c

4 files changed

Lines changed: 189 additions & 12 deletions

File tree

src/FAIR/WordPress/DID/Parsers/MetadataGenerator.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,9 +556,11 @@ public static function from_path(string $path): self
556556

557557
$generator = new self($header_data, $readme_data);
558558

559-
// Try to set slug from path.
559+
// Prefer the plugin directory name, then the plugin file name.
560560
if (is_dir($path)) {
561561
$generator->set_slug(basename(rtrim($path, '/\\')));
562+
} elseif (is_file($path)) {
563+
$generator->set_slug(pathinfo($path, PATHINFO_FILENAME));
562564
}
563565

564566
return $generator;

src/FAIR/WordPress/DID/Parsers/PluginHeaderParser.php

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -285,25 +285,24 @@ public function is_valid_plugin(string $path): bool
285285
*/
286286
public function get_slug(string $path, ?array $headers = null): ?string
287287
{
288-
// Try to get from Text Domain.
289-
if (null === $headers) {
290-
$headers = $this->parse($path);
291-
}
292-
293-
if (!empty($headers['text_domain'] ?? null)) {
294-
return $headers['text_domain'];
295-
}
296-
297-
// Fall back to directory name.
288+
// Prefer the plugin directory name when available.
298289
if (is_dir($path)) {
299290
return basename(rtrim($path, '/\\'));
300291
}
301292

302-
// Fall back to filename without extension.
293+
// Fall back to the plugin file name.
303294
if (is_file($path)) {
304295
return pathinfo($path, PATHINFO_FILENAME);
305296
}
306297

298+
if (null === $headers) {
299+
$headers = $this->parse($path);
300+
}
301+
302+
if (!empty($headers['text_domain'] ?? null)) {
303+
return $headers['text_domain'];
304+
}
305+
307306
return null;
308307
}
309308
}

tests/Unit/FAIR/WordPress/DID/Parsers/MetadataGeneratorTest.php

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,37 @@ public function testSlugIsTextDomain(): void
8888
$this->assertSame('my-test-plugin', $metadata['slug']);
8989
}
9090

91+
/**
92+
* Test slug prefers plugin directory over file name and text domain
93+
*/
94+
public function testFromPathSlugPrefersPluginDirectory(): void
95+
{
96+
$plugin_dir = $this->createTempPluginDirectory('plugin-dir-slug', 'plugin-file-slug.php', 'header-text-domain');
97+
98+
try {
99+
$metadata = MetadataGenerator::from_path($plugin_dir)->generate();
100+
$this->assertSame('plugin-dir-slug', $metadata['slug']);
101+
} finally {
102+
$this->removeTempPath(dirname($plugin_dir));
103+
}
104+
}
105+
106+
/**
107+
* Test slug prefers plugin file name over text domain for file paths
108+
*/
109+
public function testFromPathSlugPrefersPluginFileName(): void
110+
{
111+
$plugin_dir = $this->createTempPluginDirectory('plugin-dir-slug', 'plugin-file-slug.php', 'header-text-domain');
112+
$plugin_file = $plugin_dir . DIRECTORY_SEPARATOR . 'plugin-file-slug.php';
113+
114+
try {
115+
$metadata = MetadataGenerator::from_path($plugin_file)->generate();
116+
$this->assertSame('plugin-file-slug', $metadata['slug']);
117+
} finally {
118+
$this->removeTempPath(dirname($plugin_dir));
119+
}
120+
}
121+
91122
/**
92123
* Test name from header
93124
*/
@@ -288,4 +319,57 @@ public function testSecurityFieldFromHeader(): void
288319
$this->assertIsArray($metadata['security']);
289320
$this->assertSame('security@example.com', $metadata['security'][0]['email']);
290321
}
322+
323+
/**
324+
* Create a temporary plugin directory for from_path tests.
325+
*/
326+
private function createTempPluginDirectory(string $directory_name, string $file_name, string $text_domain): string
327+
{
328+
$base_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('did-manager-metadata-', true);
329+
$plugin_dir = $base_path . DIRECTORY_SEPARATOR . $directory_name;
330+
331+
mkdir($plugin_dir, 0777, true);
332+
333+
$plugin_header = <<<PHP
334+
<?php
335+
/**
336+
* Plugin Name: Temporary Test Plugin
337+
* Text Domain: {$text_domain}
338+
*/
339+
PHP;
340+
341+
file_put_contents($plugin_dir . DIRECTORY_SEPARATOR . $file_name, $plugin_header);
342+
343+
return $plugin_dir;
344+
}
345+
346+
/**
347+
* Remove a temporary path recursively.
348+
*/
349+
private function removeTempPath(string $path): void
350+
{
351+
if (is_file($path)) {
352+
unlink($path);
353+
return;
354+
}
355+
356+
if (!is_dir($path)) {
357+
return;
358+
}
359+
360+
$items = scandir($path);
361+
if (false === $items) {
362+
return;
363+
}
364+
365+
foreach ($items as $item) {
366+
if ('.' === $item || '..' === $item) {
367+
continue;
368+
}
369+
370+
$this->removeTempPath($path . DIRECTORY_SEPARATOR . $item);
371+
}
372+
373+
rmdir($path);
374+
}
291375
}

tests/Unit/FAIR/WordPress/DID/Parsers/PluginHeaderParserTest.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,45 @@ public function testParseTextDomain(): void
118118
$this->assertSame('my-test-plugin', $result['text_domain']);
119119
}
120120

121+
/**
122+
* Test slug prefers plugin directory over file name and text domain
123+
*/
124+
public function testGetSlugPrefersPluginDirectory(): void
125+
{
126+
$plugin_dir = $this->createTempPluginDirectory('plugin-dir-slug', 'main-plugin.php', 'header-text-domain');
127+
128+
try {
129+
$this->assertSame('plugin-dir-slug', $this->parser->get_slug($plugin_dir));
130+
} finally {
131+
$this->removeTempPath(dirname($plugin_dir));
132+
}
133+
}
134+
135+
/**
136+
* Test slug prefers plugin file name over text domain for file paths
137+
*/
138+
public function testGetSlugPrefersPluginFileName(): void
139+
{
140+
$plugin_dir = $this->createTempPluginDirectory('plugin-dir-slug', 'plugin-file-slug.php', 'header-text-domain');
141+
$plugin_file = $plugin_dir . DIRECTORY_SEPARATOR . 'plugin-file-slug.php';
142+
143+
try {
144+
$this->assertSame('plugin-file-slug', $this->parser->get_slug($plugin_file));
145+
} finally {
146+
$this->removeTempPath(dirname($plugin_dir));
147+
}
148+
}
149+
150+
/**
151+
* Test slug falls back to text domain when no path signal is available
152+
*/
153+
public function testGetSlugFallsBackToTextDomain(): void
154+
{
155+
$headers = $this->parser->parse_content($this->getStandardHeader());
156+
157+
$this->assertSame('my-test-plugin', $this->parser->get_slug('missing-plugin-path', $headers));
158+
}
159+
121160
/**
122161
* Test parsing requires at least
123162
*/
@@ -247,4 +286,57 @@ public function testno_commentBlockReturnsEmptyArray(): void
247286
$result = $this->parser->parse_content($no_comment);
248287
$this->assertEmpty($result);
249288
}
289+
290+
/**
291+
* Create a temporary plugin directory for slug tests.
292+
*/
293+
private function createTempPluginDirectory(string $directory_name, string $file_name, string $text_domain): string
294+
{
295+
$base_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('did-manager-plugin-', true);
296+
$plugin_dir = $base_path . DIRECTORY_SEPARATOR . $directory_name;
297+
298+
mkdir($plugin_dir, 0777, true);
299+
300+
$plugin_header = <<<PHP
301+
<?php
302+
/**
303+
* Plugin Name: Temporary Test Plugin
304+
* Text Domain: {$text_domain}
305+
*/
306+
PHP;
307+
308+
file_put_contents($plugin_dir . DIRECTORY_SEPARATOR . $file_name, $plugin_header);
309+
310+
return $plugin_dir;
311+
}
312+
313+
/**
314+
* Remove a temporary path recursively.
315+
*/
316+
private function removeTempPath(string $path): void
317+
{
318+
if (is_file($path)) {
319+
unlink($path);
320+
return;
321+
}
322+
323+
if (!is_dir($path)) {
324+
return;
325+
}
326+
327+
$items = scandir($path);
328+
if (false === $items) {
329+
return;
330+
}
331+
332+
foreach ($items as $item) {
333+
if ('.' === $item || '..' === $item) {
334+
continue;
335+
}
336+
337+
$this->removeTempPath($path . DIRECTORY_SEPARATOR . $item);
338+
}
339+
340+
rmdir($path);
341+
}
250342
}

0 commit comments

Comments
 (0)