Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Gutenberg block for adding a module to a course #1966

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"presets": [
[ "env", {
"modules": false,
"targets": {
"browsers": [
"last 2 Chrome versions",
"last 2 Firefox versions",
"last 2 Safari versions",
"last 2 Edge versions",
"last 2 Opera versions",
"last 2 iOS versions",
"last 1 Android version",
"last 1 ChromeAndroid version",
"ie 11",
"> 1%"
]
}
} ]
],
"plugins": [
"transform-object-rest-spread",
[ "transform-react-jsx", {
"pragma": "wp.element.createElement"
} ]
]
}
32 changes: 30 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module.exports = {
"parser": "babel-eslint",
"env": {
"browser": true,
"es6": true
Expand All @@ -9,12 +10,29 @@ module.exports = {
"woo_localized_data": true,
"wp": true
},
"extends": "eslint:recommended",
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
}
},
"plugins": [
"react"
],
"settings": {
"react": {
"pragma": "wp"
}
},
"rules": {
"indent": [
"error",
"tab"
],
"jsx-quotes": "error",
"linebreak-style": [
"error",
"unix"
Expand All @@ -23,9 +41,19 @@ module.exports = {
"error",
"single"
],
"react/display-name": "off",
"react/jsx-curly-spacing": [ "error", "always" ],
"react/jsx-equals-spacing": "error",
"react/jsx-indent": [ "error", "tab" ],
"react/jsx-indent-props": [ "error", "tab" ],
"react/jsx-key": "error",
"react/jsx-tag-spacing": "error",
"react/no-children-prop": "off",
"react/no-find-dom-node": "warn",
"react/prop-types": "off",
"semi": [
"error",
"always"
]
}
};
};
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ node_modules/*
vendor/*
docs.woothemes.com/*
tests/images/test-*
includes/blocks/**/build
123 changes: 123 additions & 0 deletions includes/blocks/module/class-sensei-block-module.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php
/**
* Sensei Block Module Class
*
* Gutenblock for rendering a module.
*
* @package Content
* @author Automattic
*
* @since 1.10.0
*/

class Sensei_Block_Module {
private $module;

public function __construct() {
if ( is_admin() ) {
add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ) );
} else {
if ( function_exists( 'register_block_type' ) ) {
register_block_type( 'sensei/module', array(
'render_callback' => array( $this, 'render_module' ),
) );
}
}
}

public function enqueue_block_editor_assets() {
wp_enqueue_script(
'sensei-block-module',
Sensei()->plugin_url . 'includes/blocks/module/build/index.js',
array( 'wp-blocks', 'wp-i18n', 'wp-element' ),
Sensei()->version
);

wp_enqueue_style(
'sensei-block-module-editor',
Sensei()->plugin_url . 'includes/blocks/module/build/style.css',
array( 'wp-blocks' ),
Sensei()->version
);

wp_enqueue_style(
'sensei-block-module-frontend',
Sensei()->plugin_url . 'assets/css/frontend/sensei.css',
array( 'wp-blocks' ),
Sensei()->version
);

wp_enqueue_style(
'sensei-block-module',
Sensei()->plugin_url . 'assets/css/modules-frontend.css',
array( 'wp-blocks' ),
Sensei()->version
);
}

public function render_module( $attributes ) {
$this->module = get_term_by( 'id', $attributes['moduleId'], 'module' );

include( 'templates/block-module.php' );
}

public function get_module_id() {
/**
* Filter the module ID.
*
* This fires within the get_module_id function.
*
* @since 1.9.7
*
* @param int $this->module->term_id Module ID.
*/
return apply_filters( 'sensei_the_module_id', $this->module->term_id );
}

public function get_module_title() {
global $post;

/**
* Filter the module title.
*
* This fires within the get_module_title function.
*
* @since 1.9.0
*
* @param string $this->module->name Module title.
* @param int $this->module->term_id Module ID.
* @param string $course_id Course ID.
*/
return apply_filters( 'sensei_the_module_title', $this->module->name, $this->module->term_id, $post->ID );
}

public function get_module_description() {
/**
* Filter the module description.
*
* This fires within the get_module_description function.
*
* @param string $this->module->description Module Description.
*/
return apply_filters( 'sensei_the_module_description', $this->module->description );
}

public function get_module_url() {
global $post;

$module_url = get_term_link( $this->module, 'module' );

/**
* Filter the module permalink url.
*
* This fires within the get_module_url function.
*
* @since 1.9.0
*
* @param string $module_url Module URL.
* @param int $this->module->term_id Module ID.
* @param string $post->ID Course ID.
*/
return apply_filters( 'sensei_the_module_permalink', $module_url, $this->module->term_id, $post->ID );
}
}
76 changes: 76 additions & 0 deletions includes/blocks/module/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { withAPIData } = wp.components;

import './style.scss';
import { get } from 'lodash';

registerBlockType( 'sensei/module', {
title: 'Module',
icon: 'list-view',
category: 'widgets',
supportHTML: false,
attributes: {
moduleId: { type: 'number' },
},

edit: withAPIData( props => {
const moduleId = get( props, [ 'attributes', 'moduleId' ] );

return {
module: `/sensei/v1/modules${ moduleId ? '/' + moduleId: '' }`,
modules: '/sensei/v1/modules',
};
} )( props => {
const moduleId = get( props, [ 'attributes', 'moduleId' ] );
const module = get( props, [ 'module', 'data' ], [] );
const modules = get( props, [ 'modules', 'data' ], [] );

const handleModuleChange = event => props.setAttributes( { moduleId: event.target.value } );

return (
<div>
{ modules &&
<form>
<select onChange={ handleModuleChange }>
<option value="-1" selected={ moduleId === -1 }>{ __( 'Select a Module' ) }</option>
{ modules.map( ( { id, name } ) => (
<option
selected={ moduleId === id }
value={ id }>
{ name }
</option>
) ) }
</select>
</form>
}

{ module &&
<article className="module">
{ module.name &&
<header>
<h2>
<a href="#" title={ module.name }>
{ module.name }
</a>
</h2>
</header>
}

{ module.description &&
<section className="entry">
<p className="module-description">
{ module.description }
</p>
</section>
}
</article>
}
</div>
);
} ),

save: () => {
return null;
}
} );
4 changes: 4 additions & 0 deletions includes/blocks/module/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
select {
min-width: 50%;
margin-bottom: 10px;
}
87 changes: 87 additions & 0 deletions includes/blocks/module/templates/block-module.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php
if ( ! defined( 'ABSPATH' ) ) exit;

/**
* Display a course module.
*
* @author Automattic
* @package Sensei
* @category Templates
* @version 1.10.0
*/
?>

<?php
/**
* Hook runs inside single-course/course-modules.php.
*
* It runs before the modules are shown. This hook fires on the single course page.
* It will show irrespective of whether or not the course has any modules.
*
* @since 1.10.0
*
*/
do_action( 'sensei_single_course_modules_before' );
?>

<article class="module">
<?php
/**
* Hook runs inside single-course/course-modules.php.
*
* It runs inside the if statement after the article tag opens just before the modules are shown.
* This hook will NOT fire if there are no modules to show.
*
* @since 1.9.0
* @since 1.9.7 Added the module ID to the parameters.
*
* @hooked Sensei()->modules->course_modules_title - 20
*
* @param int get_module_id() Module ID.
*/
do_action( 'sensei_single_course_modules_inside_before', $this->get_module_id() );
?>

<header>
<h2>
<a
href="<?php echo esc_url_raw( $this->get_module_url() ); ?>"
title="<?php echo esc_attr( $this->get_module_title() );?>">
<?php echo esc_html( $this->get_module_title() ); ?>
</a>
</h2>
</header>

<section class="entry">
<p class="module-description">
<?php echo esc_html( $this->get_module_description() ); ?>
</p>
</section>

<?php
/**
* Hook runs inside single-course/course-modules.php.
*
* It runs before the closing article tag directly after the modules.
* This hook will not trigger if there are no modules to show.
*
* @since 1.9.0
* @since 1.9.7 Added the module ID to the parameters.
*
* @param int sensei_get_the_module_id() Module ID.
*/
do_action( 'sensei_single_course_modules_inside_after', $this->get_module_id() );
?>

</article>

<?php
/**
* Hook runs inside single-course/course-modules.php
*
* It runs after the modules are shown. This hook fires on the single course page, but only if the course has modules.
*
* @since 1.10.0
*/
do_action('sensei_single_course_modules_after');
?>
Loading