Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jacklenox committed Jan 24, 2017
0 parents commit fc50840
Show file tree
Hide file tree
Showing 6 changed files with 477 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Ulmus

A proof of concept WordPress theme written in Elm.
21 changes: 21 additions & 0 deletions elm-package.json
Original file line number Diff line number Diff line change
@@ -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"
}
81 changes: 81 additions & 0 deletions functions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php
/**
* Ulmus functions and definitions.
*
* @link https://developer.wordpress.org/themes/basics/theme-functions/
*
* @package Ulmus
*/

if ( ! function_exists( 'ulmus_setup' ) ) :
/**
* Sets up theme defaults and registers support for various WordPress features.
*
* Note that this function is hooked into the after_setup_theme hook, which
* runs before the init hook. The init hook is too late for some features, such
* as indicating support for post thumbnails.
*/
function ulmus_setup() {
/*
* Make theme available for translation.
* Translations can be filed in the /languages/ directory.
* If you're building a theme based on Ulmus, use a find and replace
* to change 'ulmus' to the name of your theme in all the template files.
*/
load_theme_textdomain( 'ulmus', get_template_directory(). '/languages' );

// Add default posts and comments RSS feed links to head.
add_theme_support( 'automatic-feed-links' );

/*
* Let WordPress manage the document title.
* By adding theme support, we declare that this theme does not use a
* hard-coded <title> 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' );
34 changes: 34 additions & 0 deletions index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
/**
* The header for our theme.
*
* This is the template that displays all of the <head> section and everything up until <div id="content">
*
* @link https://developer.wordpress.org/themes/basics/template-files/#template-partials
*
* @package Ulmus
*/

?><!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="profile" href="http://gmpg.org/xfn/11">

<?php wp_head(); ?>
</head>

<body id="body" <?php body_class(); ?>>


<?php wp_footer(); ?>

<script>
var node = document.getElementById( 'body' );
var app = Elm.Ulmus.embed( node );
app.ports.wpOptions.send( 'http://wp-rest-api-demo.dev/wp-json/wp/v2/posts' );
</script>

</body>
</html>
247 changes: 247 additions & 0 deletions src/Ulmus.elm
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit fc50840

Please sign in to comment.