Skip to content

Instantly share code, notes, and snippets.

@krisahil
Last active January 27, 2023 12:05
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krisahil/3281406eb3936b629a88af0849243356 to your computer and use it in GitHub Desktop.
Save krisahil/3281406eb3936b629a88af0849243356 to your computer and use it in GitHub Desktop.
MkDocs served via Drupal 7 private file system

MkDocs is a great documentation framework, and Drupal is a great backend CMS. While you can use Drupal's hook_help(), if you have a lot of application-specific documentation, you may want to use a dedicated documentation tool. But how to integrate the documentation into the CMS?

I wanted a solution which would:

  • Use the same Git repository for docs (e.g., for MkDocs) as for Drupal. Being on the same repository ensures that we can write docs for MkDocs as we also write code for Drupal.
  • Commit only the docs source to Git, not the compiled docs from MkDocs
    • This means the docs would need to be compiled and then deployed to the production server.
  • Protect the compiled docs behind user access. Ideally, could use Drupal user system to only allow access to specific users.

We tried a few approaches, but each violated the above rules. Then someone suggested using Drupal's private file system ("private://") to control access. This actually worked! Here is the overview of how we set it up:

  1. Compile MkDocs to a temporary directory, then transfer these compiled files into the private files directory in Drupal. Something like this:
# Change to the root of mkdocs.
$ cd docs
# Compiles the docs. Per our config, they are dumped to a directory called "dist".
$ mkdocs build
# Pushes the compiled docs to our server, under Drupal's private://docs/ URI.
$ rsync -a --delete dist/ destination_host:/path/to/drupal/file/files/docs/
  1. Use Drupal's hook_file_download() to control access to those compiled files. Also, set the response mime-type, so that HTML/JS/CSS gets rendered as intended in the browser.
<?php
/**
* Implements hook_file_download().
*/
function mydocs_file_download($uri) {
// Protects custom documentatation behind a Drupal permission, and ensures the
// accessed files are sent as browser files with correct content-type headers,
// not attachments. Assumes the documentation is updated to "docs" subdirectory
// of private files directory.
if ($uri === 'private://docs' || strpos($uri, 'private://docs/') === 0) {
if (!user_access('mydocs access docs')) {
return -1;
}
// Acts as a very basic web server, by redirecting to [request]/index.html
// if that file is available.
$path = parse_url($uri, PHP_URL_PATH);
$extension = pathinfo($path, PATHINFO_EXTENSION);
if (empty($extension) && file_exists($uri . '/index.html')) {
$headers['Location'] = $_SERVER['REQUEST_URI'] . '/index.html';
return $headers;
}
$headers['Content-Type'] = file_get_mimetype($uri);
return $headers;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment