├── README.md └── jekyll_export ├── jekyll_export.info └── jekyll_export.module /README.md: -------------------------------------------------------------------------------- 1 | # Drupal -> Jekyll Export 2 | 3 | A simple module for exporting content from Drupal 7, into a format (Markdown only) suitable for Jekyll. 4 | 5 | It should work out-of-the-box (provided you also install my [Markdownify module](https://github.com/lukaswhite/Drupal-Markdownify), though the code's quite simple & reasonably well documented, should you need to alter it for your needs. 6 | 7 | Once you've installed the module, browse to: 8 | 9 | _admin/config/system/jekyll-export_ 10 | 11 | ..select the content types to export, enter the name of the layout you want the YAML to specify, and hit "Run Export". 12 | 13 | The result: a zip file, containing all the specified nodes in Markdown format. You should then be able to copy the contents into the _posts folder of your Jekyll site. 14 | 15 | 16 | 17 | Lukas White 18 | hello@lukaswhite.com -------------------------------------------------------------------------------- /jekyll_export/jekyll_export.info: -------------------------------------------------------------------------------- 1 | name = Jekyll Export 2 | description = A simple exporter to help migrate from Drupal to Jekyll, using Markdown 3 | package = Other 4 | version = VERSION 5 | core = 7.x 6 | dependencies = markdownify 7 | configure = admin/config/system/jekyll-export 8 | -------------------------------------------------------------------------------- /jekyll_export/jekyll_export.module: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | 9 | /** 10 | * Implements hook_menu(). 11 | */ 12 | function jekyll_export_menu() 13 | { 14 | $items = array(); 15 | 16 | // administrative items 17 | $items['admin/config/system/jekyll-export'] = array( 18 | 'title' => 'Jekyll Export', 19 | 'page callback' => 'drupal_get_form', 20 | 'page arguments' => array('jekyll_export_form'), 21 | 'access arguments' => array('administer site configuration'), 22 | 'type' => MENU_NORMAL_ITEM 23 | ); 24 | 25 | return $items; 26 | } 27 | 28 | /** 29 | * Form definition for the jekyll_export form. 30 | * 31 | * Collects parameters for the export. 32 | */ 33 | function jekyll_export_form($form, &$form_state) { 34 | 35 | $nodes = node_type_get_names(); 36 | 37 | $form['types'] = array( 38 | '#type' => 'checkboxes', 39 | '#title' => t('Types'), 40 | '#default_value' => array(), 41 | '#options' => $nodes, 42 | '#description' => t('Select which content types to export.'), 43 | ); 44 | 45 | $form['layout'] = array( 46 | '#type' => 'textfield', 47 | '#title' => t('Layout name'), 48 | '#required' => TRUE, 49 | '#default_value' => 'post', 50 | ); 51 | 52 | $form['unpublished'] = array( 53 | '#type' => 'checkbox', 54 | '#title' => t('Include unpublished nodes?'), 55 | '#default_value' => FALSE, 56 | ); 57 | 58 | $form['submit'] = array( 59 | '#type' => 'submit', 60 | '#value' => t('Run Export'), 61 | ); 62 | 63 | return $form; 64 | 65 | } 66 | 67 | /** 68 | * Validate function for the jekyll_export form. 69 | */ 70 | function jekyll_export_form_validate($form, &$form_state) { 71 | 72 | $types = array_filter($form_state['values']['types']); 73 | if (!$types) { 74 | form_set_error('types', t('You must select at least one content type.')); 75 | } 76 | 77 | } 78 | 79 | /** 80 | * Submit function for the jekyll_export form. 81 | */ 82 | function jekyll_export_form_submit($form, &$form_state) { 83 | 84 | $types = array_filter($form_state['values']['types']); 85 | $layout = $form_state['values']['layout']; 86 | jekyll_export_do_export($types, $layout); 87 | } 88 | 89 | /** 90 | * Run the export. 91 | * 92 | * Converts the content of the specified types to markdown, and creates a zip containing them. 93 | */ 94 | function jekyll_export_do_export($types, $layout) 95 | { 96 | // Create the Jekyll Export temp folder 97 | $directory = 'temporary://jekyll-export'; 98 | $success = file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); 99 | 100 | // Now create a directory for this export, using the current timestamp 101 | $directory .= '/' . date('YmdHis'); 102 | $success = file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); 103 | 104 | // Check the path to the required Markdownfiy library 105 | $path = libraries_get_path('markdownify'); 106 | 107 | // Load the Markdownify library 108 | libraries_load('markdownify'); 109 | 110 | $keephtml = true; 111 | $md = new Markdownify('Foo', MDFY_BODYWIDTH, $keephtml); 112 | 113 | $query = new EntityFieldQuery(); 114 | $query->entityCondition('entity_type', 'node') 115 | ->entityCondition('bundle', $types) 116 | ->propertyCondition('status', 1); 117 | 118 | 119 | $query->propertyOrderBy('created', 'ASC'); 120 | 121 | $entities = $query->execute(); 122 | 123 | if (count($entities)) { 124 | $nids = array_keys($entities['node']); 125 | $nodes = node_load_multiple($nids); 126 | 127 | } 128 | 129 | $files = array(); 130 | 131 | $archive_filename = 'export_' . REQUEST_TIME . '.zip'; 132 | $archive_uri = 'temporary://' . $archive_filename; 133 | $zip = new ZipArchive; 134 | if ($zip->open(drupal_realpath($archive_uri), ZipArchive::CREATE) === TRUE) { 135 | 136 | foreach ($nodes as $node) { 137 | 138 | // Extract the body 139 | $fields = field_get_items('node', $node, 'body'); 140 | $body = $fields[0]['value']; 141 | 142 | // Get the path alias 143 | $path_alias = drupal_get_path_alias('node/'.$node->nid); 144 | // ..get the part after the last /, if appropriate 145 | if (strpos($path_alias, '/')) { 146 | $alias = substr($path_alias, (strripos($path_alias, '/')+1)); 147 | } else { 148 | $alias = $path_alias; 149 | } 150 | // Build the filename 151 | $filename = date('Y-m-d', $node->created) . '-' . $alias . '.md'; 152 | 153 | // Now get the markdown 154 | $markdown = $md->parseString($body); 155 | 156 | // Generate the YAML 157 | $yaml = sprintf("---\nlayout: %s\ntitle: \"%s\"\ndate: %s\n---\n\n", $layout, $node->title, date('Y-m-d H:i:s', $node->created)); 158 | 159 | // contents of the filw are the YAML followed by the Markdown 160 | $contents = $yaml . $markdown; 161 | 162 | // and create the file 163 | file_unmanaged_save_data($contents, $directory . '/' . $filename, $replace = FILE_EXISTS_RENAME); 164 | 165 | // ...and add it to the zip file 166 | $zip->addFile(drupal_realpath($directory . '/' . $filename), $filename); 167 | } 168 | 169 | $zip->close(); 170 | 171 | // Most of this is only necessary because of IE 172 | header("Cache-Control: public"); 173 | header("Content-Type: application/octet-stream"); 174 | header("Cache-Control: no-store, no-cache, must-revalidate"); 175 | header("Cache-Control: post-check=0, pre-check=0"); 176 | header("Content-Disposition: attachment; filename=\"$archive_filename\";" ); 177 | header("Content-Transfer-Encoding: binary"); 178 | 179 | $fp = fopen(drupal_realpath($archive_uri), 'rb'); 180 | fpassthru($fp); 181 | drupal_exit(); 182 | 183 | } 184 | 185 | 186 | drupal_set_message('Content Exported'); 187 | } --------------------------------------------------------------------------------