{"id":19433163,"url":"https://github.com/ssnepenthe/simple-wp-routing","last_synced_at":"2026-05-16T02:07:34.559Z","repository":{"id":38331260,"uuid":"444986420","full_name":"ssnepenthe/simple-wp-routing","owner":"ssnepenthe","description":"Syntactic sugar over the WP_Rewrite API so we can pretend that WordPress has a modern router.","archived":false,"fork":false,"pushed_at":"2024-01-05T17:20:49.000Z","size":391,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-08T01:29:19.843Z","etag":null,"topics":["toy","wordpress"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ssnepenthe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-06T00:05:55.000Z","updated_at":"2023-11-21T20:55:53.000Z","dependencies_parsed_at":"2024-11-10T14:42:20.697Z","dependency_job_id":"66748601-e454-4ed2-9ea6-bd1f32725414","html_url":"https://github.com/ssnepenthe/simple-wp-routing","commit_stats":null,"previous_names":["ssnepenthe/simple-wp-routing"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssnepenthe%2Fsimple-wp-routing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssnepenthe%2Fsimple-wp-routing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssnepenthe%2Fsimple-wp-routing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssnepenthe%2Fsimple-wp-routing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ssnepenthe","download_url":"https://codeload.github.com/ssnepenthe/simple-wp-routing/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240612944,"owners_count":19829099,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["toy","wordpress"],"created_at":"2024-11-10T14:38:40.471Z","updated_at":"2026-05-16T02:07:29.540Z","avatar_url":"https://github.com/ssnepenthe.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# simple-wp-routing\n\nSyntactic sugar over the `WP_Rewrite` API so we can pretend that WordPress has a modern router.\n\n## Warning\n\nThis package is currently in development and is subject to breaking changes without notice until v1.0 has been tagged.\n\nIt is one in a series of [WordPress toys](https://github.com/ssnepenthe?tab=repositories\u0026q=topic%3Atoy+topic%3Awordpress\u0026type=\u0026language=\u0026sort=) I have been working on with the intention of exploring ways to modernize the feel of working with WordPress.\n\nAs the label suggests, it should be treated as a toy.\n\n## Installation\n\n```sh\ncomposer require ssnepenthe/simple-wp-routing\n```\n\n## Basic Usage\n\nIntended usage is via the Router class.\n\n### Overview\n\n```php\nuse SimpleWpRouting\\Exception\\NotFoundHttpException;\nuse SimpleWpRouting\\Responder\\JsonResponder;\nuse SimpleWpRouting\\Router;\n\n// Create a router instance.\n$router = new Router();\n\n// Optional - configure your router via various available setters.\n// At a minimum it is recommended to set a route prefix in order to avoid conflicts with core and other plugins.\n$router-\u003esetPrefix('pfx_');\n\n// Wire your router up with WordPress.\n$router-\u003einitialize(\n\n  // The initialize method accepts a callback which is where you should add all of your routes.\n  function (Router $router) {\n\n    // Routes are registered via HTTP method shortcuts on the router instance.\n    $route = $router-\u003eget(\n\n      // Route syntax comes from FastRoute.\n      'api/users/{user}',\n\n      // Route handlers are automatically invoked for their corresponding route/HTTP method pair.\n      function (array $vars) {\n\n        // Handlers receive an array of matched route variables by default.\n        $user = getUserDataById((int) $vars['user']);\n\n        // HTTP exceptions are automatically converted to error responses.\n        if (null === $user) {\n          throw new NotFoundHttpException();\n        }\n\n        // Handlers can optionally return a responder instance.\n        return new JsonResponder($user);\n      }\n    );\n\n    // Routes can optionally be configured with an active callback.\n    $route-\u003esetIsActiveCallback(function () {\n\n      // Return true to enable this route, false to disable it.\n      return isApiUserEndpointEnabled();\n    });\n  }\n);\n```\n\n### Route Syntax\n\nThe default route syntax comes from FastRoute.\n\nRoute variables are wrapped in curly brackets and match the regex pattern `[^/]+` by default (e.g. `users/{user}`). Custom regex patterns can be provided using a `name:pattern` syntax (e.g. `users/{user:\\d+}`). Capture groups are not allowed in custom patterns.\n\nOptional route segments are defined using square brackets (e.g. `users/{user}[/favorites]`). Nested optional segments are also supported (e.g. `users[/{user}[/favorites]]`). Optional segments are only supported at the end of route strings.\n\nIf you have a route syntax that you prefer over FastRoute, you can provide a custom route parser. Your parser must implement `\\SimpleWpRouting\\Parser\\RouteParserInterface`. Refer to the included `tests/Unit/Parser/FastRouteRouteParserTest.php` file to understand route parser requirements.\n\n### Route Handlers\n\nRoute handlers are automatically called within the `'parse_request'` hook when their corresponding route/method pair matches the current request.\n\nAllowed types for handlers are defined by the callable resolver. With the default config, handlers must be a PHP callable. If using the PSR container callable resolver, handlers may also be a string identifier that resolves a callable from your container or a callable shaped array where index 0 is a string identifier that resolves an object from your container and index 1 is a callable method on that object.\n\nThe function signature is defined by the configured invoker. The default invoker provides an array containing all matched route variables keyed by variable name. The PHP-DI invoker provides matched route variables directly by name.\n\nHTTP exceptions can be used as a convenient escape hatch from handlers.\n\n#### NotFoundHttpException\n\nThis is currently the only non-internal HTTP exception and can be used to show a 404 page.\n\n```php\nuse SimpleWpRouting\\NotFoundHttpException;\n\n$router-\u003eget('books/{book}', function (array $vars) {\n  if (! $book = getBookById($vars['book'])) {\n    throw new NotFoundHttpException();\n  }\n\n  // ...\n});\n```\n\nRoute handlers can optionally return an instance of `SimpleWpRouting\\Responder\\ResponderInterface`. The `respond` method on the returned responder will automatically be invoked on the WordPress `parse_request` action.\n\nThis allows common behavior to easily be wrapped up for reuse.\n\nThe following basic responder implementations are included:\n\n#### JsonResponder\n\n```php\nuse SimpleWpRouting\\Responder\\JsonResponder;\n\n$router-\u003eget('api/products', function () {\n  return new JsonResponder(['products' =\u003e getAllProducts()]);\n});\n```\n\nResponses are sent using `wp_send_json_success` or `wp_send_json_error` depending on the status code, so data will be available at `response.data`.\n\n#### QueryResponder\n\n```php\nuse SimpleWpRouting\\Responder\\QueryResponder;\n\n$router-\u003eget('products/random[/{count}]', function (array $vars) {\n  $count = (int) ($vars['count'] ?? 5);\n\n  return new QueryResponder([\n    'post_type' =\u003e 'pfx_product',\n    'orderby' =\u003e 'rand',\n    'posts_per_page' =\u003e clamp($count, 1, 10),\n  ]);\n});\n```\n\nQuery variables are applied on the `parse_request` hook, before the main query is run.\n\n#### RedirectResponder\n\n```php\nuse SimpleWpRouting\\Responder\\RedirectResponder;\n\n$router-\u003eget('r/{redirect}', function (array $vars) {\n  $location = getRedirectLocationById($vars['redirect']);\n\n  return new RedirectResponder($location);\n});\n```\n\nRedirects are sent using `wp_safe_redirect` by default. You can pass `false` as the 4th constructor argument to use `wp_redirect` instead:\n\n```php\nreturn new RedirectResponder($location, 302, 'WordPress', false);\n```\n\n#### TemplateResponder\n\n```php\nuse SimpleWpRouting\\Responder\\TemplateResponder;\n\n$router-\u003eget('thank-you', function () {\n  return new TemplateResponder(__DIR__ . '/templates/thank-you.php');\n});\n```\n\nTemplates are loaded via the `template_include` filter.\n\n### Active Callbacks\n\nAllowed types for active callbacks are also defined by the configured callable resolver.\n\nActive callbacks should return a boolean value - when true the route will be considered active, when false the route will be considered inactive.\n\nRewrite rules and query variables for inactive routes are still registered with WordPress, but visiting the route will result in a 404 response.\n\n### Error Templates\n\nBasic 400 and 405 error templates are included with styling loosely modeled after the twentytwentytwo 404 template.\n\nThese can be overridden in themes by creating `400.php` and `405.php` templates or `400.html` and `405.html` block templates.\n\n### Likely Changes\n\nTypes of various SPL exceptions used throughout the package as well as revisiting the general hierarchy of package exceptions.\n\nResponder internals - partials concept is a bit convoluted/over-engineered. Any changes shouldn't affect the top-level responders meant for use by end-users.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssnepenthe%2Fsimple-wp-routing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fssnepenthe%2Fsimple-wp-routing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssnepenthe%2Fsimple-wp-routing/lists"}