diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c103bd7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# Ulmus
+
+A proof of concept WordPress theme written in Elm.
diff --git a/elm-package.json b/elm-package.json
new file mode 100644
index 0000000..4ca8a0b
--- /dev/null
+++ b/elm-package.json
@@ -0,0 +1,21 @@
+{
+ "version": "1.0.0",
+ "summary": "helpful summary of your project, less than 80 characters",
+ "repository": "https://github.com/user/project.git",
+ "license": "BSD3",
+ "source-directories": [
+ "src"
+ ],
+ "exposed-modules": [],
+ "native-modules": true,
+ "dependencies": {
+ "elm-lang/core": "5.0.0 <= v < 6.0.0",
+ "elm-lang/dom": "1.1.1 <= v < 2.0.0",
+ "elm-lang/html": "2.0.0 <= v < 3.0.0",
+ "elm-lang/http": "1.0.0 <= v < 2.0.0",
+ "elm-lang/navigation": "2.0.1 <= v < 3.0.0",
+ "evancz/elm-markdown": "3.0.1 <= v < 4.0.0",
+ "evancz/url-parser": "2.0.1 <= v < 3.0.0"
+ },
+ "elm-version": "0.18.0 <= v < 0.19.0"
+}
diff --git a/functions.php b/functions.php
new file mode 100644
index 0000000..f468738
--- /dev/null
+++ b/functions.php
@@ -0,0 +1,81 @@
+ tag in the document head, and expect WordPress to
+ * provide it for us.
+ */
+ add_theme_support( 'title-tag' );
+
+ /*
+ * Enable support for Post Thumbnails on posts and pages.
+ *
+ * @link https://developer.wordpress.org/themes/functionality/featured-images-post-thumbnails/
+ *
+ */
+ add_theme_support( 'post-thumbnails' );
+ }
+endif;
+add_action( 'after_setup_theme', 'ulmus_setup' );
+
+/**
+ * Enqueue scripts and styles.
+ */
+function ulmus_scripts() {
+ wp_enqueue_style( 'ulmus-style', get_stylesheet_uri() );
+
+ wp_enqueue_script( 'ulmus-theme', get_template_directory_uri() . '/ulmus.js', array(), '20170118', true );
+}
+add_action( 'wp_enqueue_scripts', 'ulmus_scripts' );
+
+function get_post_data( $posts = null ) {
+ //if ( $posts === null && ! is_404() ) {
+ $posts = $GLOBALS['wp_query']->posts;
+ //}
+ //error_log( print_r( $GLOBALS['wp_query']->posts, true ) );
+ global $wp_rest_server;
+ if ( empty( $wp_rest_server ) ) {
+ $wp_rest_server_class = apply_filters( 'wp_rest_server_class', 'WP_REST_Server' );
+ $wp_rest_server = new $wp_rest_server_class;
+ do_action( 'rest_api_init' );
+ }
+ $data = array();
+ $request = new \WP_REST_Request();
+ $request['context'] = 'view';
+ foreach ( (array) $posts as $post ) {
+ $controller = new \WP_REST_Posts_Controller( $post->post_type );
+ $data[] = $wp_rest_server->response_to_data( $controller->prepare_item_for_response( $post, $request ), true );
+ }
+ error_log( print_r( $data, true ) );
+ return $data;
+}
+
+add_action( 'wp_footer', 'get_post_data' );
diff --git a/index.php b/index.php
new file mode 100644
index 0000000..cfb18b1
--- /dev/null
+++ b/index.php
@@ -0,0 +1,34 @@
+ section and everything up until
+ *
+ * @link https://developer.wordpress.org/themes/basics/template-files/#template-partials
+ *
+ * @package Ulmus
+ */
+
+?>
+>
+
+
+
+
+
+
+
+
+>
+
+
+
+
+
+
+
+
diff --git a/src/Ulmus.elm b/src/Ulmus.elm
new file mode 100644
index 0000000..100273d
--- /dev/null
+++ b/src/Ulmus.elm
@@ -0,0 +1,247 @@
+port module Ulmus exposing (..)
+
+import Dom.Scroll exposing (toTop)
+import Html exposing (..)
+import Html.Attributes exposing (..)
+import Html.Events exposing (onClick, onWithOptions)
+import Http
+import Json.Decode as Decode exposing (Decoder, field, at, succeed)
+import Markdown
+import Navigation
+import UrlParser as Url exposing((>), (>), s, int, string, stringParam, top)
+
+
+-- MODEL
+
+type alias Model =
+ { route : Route
+ , history : List (Maybe Route)
+ , posts : List Post
+ , havePosts : Bool
+ , apiUrl : String
+ }
+
+
+type alias Post =
+ { id : Int
+ , date : String
+ , slug : String
+ , link : String
+ , content : String
+ , title : String
+ }
+
+
+initialModel : Route -> Model
+initialModel route =
+ { route = route
+ , history = []
+ , posts = []
+ , havePosts = False
+ , apiUrl = ""
+ }
+
+init : Navigation.Location -> ( Model, Cmd Msg )
+init location =
+ let
+ currentRoute =
+ parseLocation location
+ in
+ ( initialModel currentRoute, Cmd.none )
+
+
+-- URL PARSING
+
+
+type Route
+ = Home
+ | BlogPost Int Int Int String
+ | NotFoundRoute
+
+
+type alias PostRoute = { year : Int, month : Int, day : Int, slug : String }
+
+
+rawPost : Url.Parser (Int -> Int -> Int -> String -> slug) slug
+rawPost =
+ int > int > int > string
+
+
+route : Url.Parser (Route -> a) a
+route =
+ Url.oneOf
+ [ Url.map Home top
+ , Url.map BlogPost rawPost
+ ]
+
+
+parseLocation : Navigation.Location -> Route
+parseLocation location =
+ case (Url.parsePath route location) of
+ Just route ->
+ route
+
+ Nothing ->
+ NotFoundRoute
+
+
+-- UPDATE
+
+
+type Msg =
+ GetPosts (Result Http.Error (List Post))
+ | ApiUrl (String)
+ | NewUrl String
+ | UrlChange Navigation.Location
+ | NoOp
+
+
+update : Msg -> Model -> ( Model, Cmd Msg )
+update msg model =
+ case msg of
+ GetPosts (Ok latestPosts) ->
+ ( { model | posts = latestPosts, havePosts = True }, Cmd.none )
+
+ GetPosts (Err error) ->
+ let
+ _ = Debug.log "Oops!" error
+ in
+ (model, Cmd.none)
+
+ ApiUrl newApiUrl ->
+ ( { model | apiUrl = newApiUrl }, getPosts newApiUrl)
+
+ NewUrl url ->
+ ( model
+ , Navigation.newUrl url
+ )
+
+ UrlChange location ->
+ let
+ newRoute =
+ parseLocation location
+ in
+ ( { model | route = newRoute }, Cmd.none )
+
+ NoOp ->
+ ( model, Cmd.none )
+
+
+-- DECODERS
+
+postDecoder : Decoder Post
+postDecoder =
+ Decode.map6 Post
+ (field "id" Decode.int)
+ (field "date" Decode.string)
+ (field "slug" Decode.string)
+ (field "link" Decode.string)
+ (at ["content", "rendered"] Decode.string)
+ (at ["title", "rendered"] Decode.string)
+
+
+-- COMMANDS
+
+getPosts : String -> Cmd Msg
+getPosts apiUrl =
+ (Decode.list postDecoder)
+ |> Http.get (apiUrl ++ "posts")
+ |> Http.send GetPosts
+
+
+onPrevDefClick : msg -> Attribute msg
+onPrevDefClick message =
+ onWithOptions "click" { stopPropagation = True, preventDefault = True } (Decode.succeed message)
+
+
+-- SUBSCRIPTIONS
+
+port apiUrl : (String -> msg) -> Sub msg
+
+subscriptions : Model -> Sub Msg
+subscriptions model =
+ apiUrl ApiUrl
+
+
+-- VIEW
+
+view : Model -> Html Msg
+view model =
+ div [ id "page", class "site" ]
+ [ div [ class "content" ]
+ [ header [ id "masthead", class "site-header" ]
+ [ div [ class "site-branding" ]
+ [ h1 [ class "site-title" ] [
+ a [ href "/", onPrevDefClick (NewUrl "/") ]
+ [ text "WordPress ♥ Elm ♥ REST API" ]
+ ]
+ ]
+ ]
+ , page model
+ ]
+ ]
+
+page : Model -> Html Msg
+page model =
+ case model.route of
+ Home ->
+ viewPostList model.posts
+
+ BlogPost year month day slug ->
+ viewSinglePost model slug
+
+ NotFoundRoute ->
+ viewNotFound
+
+
+viewPostList : List Post -> Html Msg
+viewPostList posts =
+ let
+ listOfPosts =
+ List.map viewPost posts
+ in
+ div [] listOfPosts
+
+
+viewSinglePost : Model -> String -> Html Msg
+viewSinglePost model slug =
+ let
+ maybePost =
+ model.posts
+ |> List.filter (\post -> post.slug == slug)
+ |> List.head
+ in
+ case maybePost of
+ Just post ->
+ div [] [ viewPost post ]
+
+ Nothing ->
+ viewNotFound
+
+
+viewPost : Post -> Html Msg
+viewPost post =
+ section [ class "post" ]
+ [ h2 [] [
+ a [ href post.link, onPrevDefClick (NewUrl post.link) ]
+ [ text post.title ]
+ ]
+ , article [ class "content"]
+ [ Markdown.toHtml [] post.content ]
+ ]
+
+
+viewNotFound : Html Msg
+viewNotFound =
+ div []
+ [ text "Not found" ]
+
+
+main : Program Never Model Msg
+main =
+ Navigation.program UrlChange
+ { init = init
+ , view = view
+ , update = update
+ , subscriptions = subscriptions
+ }
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..5af5104
--- /dev/null
+++ b/style.css
@@ -0,0 +1,91 @@
+/*
+Theme Name: Ulmus
+Theme URI: http://underscores.me/
+Author: Jack Lenox
+Author URI: http://jacklenox.com
+Description: A WordPress theme built with Elm
+Version: 1.0.0
+License: GNU General Public License v2 or later
+License URI: http://www.gnu.org/licenses/gpl-2.0.html
+Text Domain: ulmus
+Tags:
+
+This theme, like WordPress, is licensed under the GPL.
+Use it to make something cool, have fun, and share what you've learned with others.
+
+Ulmus is based on Underscores http://underscores.me/, (C) 2012-2016 Automattic, Inc.
+Underscores is distributed under the terms of the GNU GPL v2 or later.
+
+Normalizing styles have been helped along thanks to the fine work of
+Nicolas Gallagher and Jonathan Neal http://necolas.github.com/normalize.css/
+*/
+
+body {
+ font: 12pt/1.8 -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", sans-serif;
+ max-width: 720px;
+ padding: 60px 20px;
+ margin: 0 auto;
+ color: #1a1a1a;
+}
+
+h1 {
+ font-size: 36pt;
+}
+
+h1 a:link, h1 a:visited {
+ color: #1a1a1a;
+ text-decoration: none;
+}
+
+h2 {
+ font-size: 28pt;
+ font-weight: 800;
+ margin: 0 0 20px 0;
+}
+
+h2:before {
+ content: '#';
+ display: inline-block;
+ width: 32px;
+ font-size: 24px;
+ position: relative;
+ left: -32px;
+ top: -2px;
+ margin-right: -32px;
+ color: #dddddd;
+}
+
+p {
+ margin-bottom: 30px;
+}
+
+a:link,
+a:active {
+ color: #3d88f5;
+}
+
+a:visited {
+ color: #5d9af7;
+}
+
+img {
+ max-width: 100%;
+}
+
+.avatar {
+ border-radius: 50%;
+ margin: 0 8px -6px 0;
+}
+
+.post {
+ margin-bottom: 60px;
+
+ footer {
+ margin: 40px 0 0 0;
+ }
+
+ footer span {
+ display: inline-block;
+ margin-right: 20px;
+ }
+}