├── .bowerrc ├── templates ├── play-button-shortcode-not-found.php ├── series-search-results.php ├── sermon-search-results.php ├── search-query-error.php ├── play-button-shortcode.php ├── related-links.php ├── nav.php ├── sermons-list.php ├── admin-column.css ├── play-button-shortcode-modal-videos.php ├── sermon-speaker-info.php ├── series-list.php ├── play-button-shortcode-style.css ├── list-item.php ├── searchform.php ├── searchform-xhtml.php └── list-item-style.css ├── gc-sermons.zip ├── includes ├── README.md ├── shortcodes │ ├── shortcodes-series │ │ ├── class-shortcode.php │ │ ├── class-admin.php │ │ └── class-run.php │ ├── shortcodes-recent-series │ │ ├── class-shortcode.php │ │ ├── class-run.php │ │ └── class-admin.php │ ├── shortcodes-play-button │ │ ├── class-shortcode.php │ │ ├── class-admin.php │ │ └── class-run.php │ ├── shortcodes-sermons │ │ ├── class-shortcode.php │ │ ├── class-admin.php │ │ └── class-run.php │ ├── shortcodes-recent-speaker │ │ ├── class-shortcode.php │ │ ├── class-run.php │ │ └── class-admin.php │ ├── shortcodes-search │ │ ├── class-shortcode.php │ │ ├── class-sermons-search-run.php │ │ ├── class-admin.php │ │ ├── class-series-search-run.php │ │ └── class-run.php │ ├── class-shortcodes-base.php │ ├── class-shortcodes-recent-admin-base.php │ ├── class-shortcodes-admin-base.php │ ├── class-shortcodes-run-base.php │ ├── class-shortcodes.php │ ├── shortcodes-audio-player │ │ └── class-shortcode.php │ ├── shortcodes-video-player │ │ └── class-shortcode.php │ └── shortcodes-related-links │ │ └── class-shortcode.php ├── taxonomies │ ├── class-topic.php │ ├── class-tag.php │ ├── class-scripture.php │ ├── class-taxonomies.php │ ├── class-series.php │ ├── class-speaker.php │ └── class-taxonomies-base.php ├── class-async.php ├── post-types │ └── class-post-types-base.php ├── class-style-loader.php ├── class-template-loader.php └── class-sermon-post.php ├── tests ├── test-pbs-run.php ├── test-base.php ├── test-taxonomies.php ├── test-shortcodes.php ├── test-play-button-shortcode.php ├── test-sermons.php ├── test-async.php ├── test-speaker.php ├── test-sermon-series.php ├── bootstrap.php └── test-sermon-post.php ├── bower.json ├── phpunit.xml ├── .travis.yml ├── .yo-rc.json ├── package.json ├── readme.txt ├── Dockunit.json ├── assets └── js │ ├── gc-sermons-admin.js │ ├── gc-sermon-videos.js │ └── vendor │ └── jquery.fitvids.js ├── README.md ├── .gitignore ├── composer.json ├── Gruntfile.js ├── bin └── install-wp-tests.sh ├── CHANGELOG.md ├── gc-sermons.php └── functions.php /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "assets/bower" 3 | } -------------------------------------------------------------------------------- /templates/play-button-shortcode-not-found.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /gc-sermons.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtsternberg/GC-Sermons/HEAD/gc-sermons.zip -------------------------------------------------------------------------------- /includes/README.md: -------------------------------------------------------------------------------- 1 | # GC Sermons Includes # 2 | http://dsgnwrks.pro 3 | Copyright (c) 2016 jtsternberg 4 | Licensed under the GPLv2 license. 5 | 6 | Additional PHP functionality goes here. 7 | -------------------------------------------------------------------------------- /tests/test-pbs-run.php: -------------------------------------------------------------------------------- 1 | assertTrue( class_exists( 'GCSS_Play_Button_Run') ); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /templates/series-search-results.php: -------------------------------------------------------------------------------- 1 |
2 |

output( 'search_notice' ); ?>

3 | 4 | output( 'results' ); ?> 5 |
6 | -------------------------------------------------------------------------------- /templates/sermon-search-results.php: -------------------------------------------------------------------------------- 1 |
2 |

output( 'search_notice' ); ?>

3 | 4 | output( 'results' ); ?> 5 |
6 | -------------------------------------------------------------------------------- /templates/search-query-error.php: -------------------------------------------------------------------------------- 1 |
2 |

3 |
4 | -------------------------------------------------------------------------------- /templates/play-button-shortcode.php: -------------------------------------------------------------------------------- 1 | output( 'style' ); ?> 5 | href="output( 'video_url', 'esc_url' ); ?>" 6 | > 7 | 8 | -------------------------------------------------------------------------------- /tests/test-base.php: -------------------------------------------------------------------------------- 1 | assertTrue( class_exists( 'GC_Sermons_Plugin') ); 7 | } 8 | 9 | function test_get_instance() { 10 | $this->assertTrue( gc_sermons() instanceof GC_Sermons_Plugin ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /templates/related-links.php: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 9 | -------------------------------------------------------------------------------- /tests/test-taxonomies.php: -------------------------------------------------------------------------------- 1 | assertTrue( class_exists( 'GCS_Taxonomies') ); 7 | } 8 | 9 | function test_class_access() { 10 | $this->assertTrue( gc_sermons()->taxonomies instanceof GCS_Taxonomies ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/test-shortcodes.php: -------------------------------------------------------------------------------- 1 | assertTrue( class_exists( 'GCS_Shortcodes') ); 7 | } 8 | 9 | function test_class_access() { 10 | gc_sermons()->hooks(); 11 | $this->assertTrue( gc_sermons()->shortcodes instanceof GCS_Shortcodes ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gc-sermons", 3 | "description": "Manage sermons and sermon content in WordPress", 4 | "license": "GPLv2", 5 | "authors": [ 6 | "jtsternberg" 7 | ], 8 | "private": true, 9 | "ignore": [ 10 | "**/.*", 11 | "node_modules", 12 | "bower_components", 13 | "test", 14 | "tests" 15 | ], 16 | "dependencies": { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | ./tests/ 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /templates/nav.php: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /tests/test-play-button-shortcode.php: -------------------------------------------------------------------------------- 1 | assertTrue( class_exists( 'GCS_Shortcodes_Play_Button') ); 7 | } 8 | 9 | // function test_class_access() { 10 | // $this->assertTrue( gc_sermons()->play_button instanceof GCS_Shortcodes_Play_Button ); 11 | // } 12 | } 13 | -------------------------------------------------------------------------------- /templates/sermons-list.php: -------------------------------------------------------------------------------- 1 |
2 | 7 | 8 | args ); ?> 9 |
10 | -------------------------------------------------------------------------------- /tests/test-sermons.php: -------------------------------------------------------------------------------- 1 | assertTrue( class_exists( 'GCS_Sermons') ); 7 | } 8 | 9 | function test_class_access() { 10 | $this->assertTrue( gc_sermons()->sermons instanceof GCS_Sermons ); 11 | } 12 | 13 | function test_cpt_exists() { 14 | $this->assertTrue( post_type_exists( 'gc-sermons' ) ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/test-async.php: -------------------------------------------------------------------------------- 1 | assertTrue( true ); 8 | } 9 | 10 | function test_class_exists() { 11 | $this->assertTrue( class_exists( 'GCS_Async') ); 12 | } 13 | 14 | function test_class_access() { 15 | $this->assertTrue( gc_sermons()->async instanceof GCS_Async ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/test-speaker.php: -------------------------------------------------------------------------------- 1 | assertTrue( class_exists( 'GCS_Speaker') ); 7 | } 8 | 9 | function test_class_access() { 10 | $this->assertTrue( gc_sermons()->speaker instanceof GCS_Speaker ); 11 | } 12 | 13 | function test_taxonomy_exists() { 14 | $this->assertTrue( taxonomy_exists( 'gcs-speaker' ) ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/test-sermon-series.php: -------------------------------------------------------------------------------- 1 | assertTrue( class_exists( 'GCS_Series') ); 7 | } 8 | 9 | function test_class_access() { 10 | $this->assertTrue( gc_sermons()->series instanceof GCS_Series ); 11 | } 12 | 13 | function test_taxonomy_exists() { 14 | $this->assertTrue( taxonomy_exists( 'gc-sermon-series' ) ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | notifications: 4 | email: 5 | on_success: never 6 | on_failure: change 7 | 8 | php: 9 | - 5.3 10 | - 5.5 11 | 12 | env: 13 | - WP_VERSION=latest WP_MULTISITE=0 14 | 15 | matrix: 16 | include: 17 | - php: 5.3 18 | env: WP_VERSION=latest WP_MULTISITE=1 19 | 20 | before_script: 21 | - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION 22 | 23 | script: phpunit 24 | -------------------------------------------------------------------------------- /templates/admin-column.css: -------------------------------------------------------------------------------- 1 | #tax-series { 2 | width: 150px; 3 | } 4 | 5 | .sermon-series.with-image a { 6 | display: block; 7 | position: relative; 8 | text-align: center; 9 | } 10 | 11 | .sermon-series.with-image a:hover img { 12 | opacity: .05; 13 | } 14 | 15 | .sermon-series.with-image a:hover:after { 16 | content: attr(title); 17 | position: absolute; 18 | top: 0; 19 | left: 0; 20 | padding: 8px 10%; 21 | z-index: 98; 22 | width: 80%; 23 | min-height: 40px; 24 | } 25 | -------------------------------------------------------------------------------- /templates/play-button-shortcode-modal-videos.php: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-plugin-wp": { 3 | "name": "GC Sermons", 4 | "homepage": "http://dsgnwrks.pro", 5 | "description": "Manage sermons and sermon content in WordPress", 6 | "version": "0.2.1", 7 | "author": "jtsternberg", 8 | "authoremail": "justin@dsgnwrks.pro", 9 | "authorurl": "http://dsgnwrks.pro", 10 | "license": "GPLv2", 11 | "slug": "gc-sermons", 12 | "classname": "GC_Sermons", 13 | "classprefix": "GCS_", 14 | "prefix": "gc_sermons", 15 | "year": 2016 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /templates/sermon-speaker-info.php: -------------------------------------------------------------------------------- 1 |
2 |

3 | 4 |

5 | get( 'image' ) ) : ?> 6 | 7 | output( 'image' ); ?> 8 | 9 | 10 |

11 | output( 'name' ); ?> 12 |

13 |
14 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-series/class-shortcode.php: -------------------------------------------------------------------------------- 1 | run = new GCSS_Series_Run( $plugin->sermons, $plugin->series ); 18 | $this->admin = new GCSS_Series_Admin( $this->run ); 19 | 20 | parent::hooks(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /templates/series-list.php: -------------------------------------------------------------------------------- 1 |
2 | get( 'terms' ) as $year => $terms ) : ?> 3 | get( 'remove_dates' ) ) : ?> 4 |

5 | 6 | 11 | 12 | 13 | args ); ?> 14 |
15 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-recent-series/class-shortcode.php: -------------------------------------------------------------------------------- 1 | run = new GCSS_Recent_Series_Run( $plugin->sermons ); 18 | $this->admin = new GCSS_Recent_Series_Admin( $this->run ); 19 | 20 | parent::hooks(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gc-sermons", 3 | "title": "GC Sermons", 4 | "version": "0.2.1", 5 | "description": "Manage sermons and sermon content in WordPress", 6 | "author": { 7 | "name": "jtsternberg", 8 | "url": "http://dsgnwrks.pro" 9 | }, 10 | "license": "GPLv2", 11 | "devDependencies": { 12 | "grunt": "latest", 13 | "grunt-contrib-watch": "latest", 14 | "grunt-wp-i18n": "latest", 15 | "grunt-contrib-compress": "~0.11.0", 16 | "grunt-githooks": "~0.3.1", 17 | "grunt-text-replace": "latest", 18 | "load-grunt-tasks": "latest" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-play-button/class-shortcode.php: -------------------------------------------------------------------------------- 1 | run = new GCSS_Play_Button_Run( $plugin->sermons ); 19 | $this->admin = new GCSS_Play_Button_Admin( $this->run ); 20 | 21 | parent::hooks(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-sermons/class-shortcode.php: -------------------------------------------------------------------------------- 1 | run = new GCSS_Sermons_Run( $plugin->sermons, $plugin->taxonomies ); 18 | $this->admin = new GCSS_Sermons_Admin( $this->run, $plugin->taxonomies ); 19 | 20 | parent::hooks(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-recent-speaker/class-shortcode.php: -------------------------------------------------------------------------------- 1 | run = new GCSS_Recent_Speaker_Run( $plugin->sermons ); 18 | $this->admin = new GCSS_Recent_Speaker_Admin( $this->run ); 19 | 20 | parent::hooks(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | run = new GCS_Shortcodes_Sermon_Search_Run( $plugin->sermons, $plugin->taxonomies ); 18 | $this->admin = new GCS_Shortcodes_Sermon_Search_Admin( $this->run, $plugin->taxonomies ); 19 | 20 | parent::hooks(); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /tests/test-sermon-post.php: -------------------------------------------------------------------------------- 1 | assertTrue( class_exists( 'GCS_Sermon_Post') ); 7 | } 8 | 9 | function test_class_access() { 10 | $sermons = gc_sermons()->sermons; 11 | $this->assertFalse( $sermons->most_recent() ); 12 | $this->assertEquals( 'gc-sermons', $sermons->post_type() ); 13 | 14 | // Create a post 15 | $this->factory->post->create( array( 16 | 'post_type' => $sermons->post_type(), 17 | ) ); 18 | 19 | $sermons->flush = true; 20 | 21 | // And check if we found an instance 22 | $this->assertTrue( $sermons->most_recent() instanceof GCS_Sermon_Post ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /templates/play-button-shortcode-style.css: -------------------------------------------------------------------------------- 1 | .gc-sermons-play-button { 2 | padding: 1em; 3 | } 4 | 5 | .gc-sermons-play-button.icon-size-large { 6 | font-size: 2em; 7 | } 8 | 9 | .gc-sermons-play-button.icon-size-medium { 10 | font-size: 1em; 11 | } 12 | 13 | .gc-sermons-play-button.icon-size-small { 14 | font-size: .5em; 15 | } 16 | 17 | #gc-video-overlay { 18 | display: block; 19 | width: 100%; 20 | position: fixed; 21 | left: 0; 22 | top: 0; 23 | height: 100%; 24 | background: rgba(0,0,0,.62); 25 | z-index: 9999998; 26 | } 27 | 28 | .gc-sermons-modal { 29 | position: absolute; 30 | display: block; 31 | top: 50%; 32 | left: 0; 33 | width: 90%; 34 | margin-left: 5%; 35 | } 36 | 37 | .gcinvisible { 38 | visibility: hidden; 39 | } 40 | -------------------------------------------------------------------------------- /includes/shortcodes/class-shortcodes-base.php: -------------------------------------------------------------------------------- 1 | hooks(); 33 | } 34 | 35 | public function hooks() { 36 | $this->run->hooks(); 37 | $this->admin->hooks(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /templates/list-item.php: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | 4 | maybe_output( 'image', '', 'do_image' ); ?> 5 | 6 |
    7 |
    8 | 9 | 10 | 11 | 14 | 15 | 16 |
    12 |

    output( 'name' ); ?>

    13 |
    17 |
    18 |
    19 | 20 |
    21 | maybe_output( 'description', '', 'do_description' ); ?> 22 |
    23 | 24 |
  • 25 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | === GC Sermons === 2 | Contributors: jtsternberg 3 | Donate link: http://dsgnwrks.pro 4 | Tags: 5 | Requires at least: 4.4 6 | Tested up to: 4.9.8 7 | Stable tag: 0.2.1 8 | License: GPLv2 9 | License URI: http://www.gnu.org/licenses/gpl-2.0.html 10 | 11 | 12 | == Description == 13 | 14 | Manage sermons and sermon content in WordPress 15 | 16 | == Installation == 17 | 18 | = Manual Installation = 19 | 20 | 1. Upload the entire `/gc-sermons` directory to the `/wp-content/plugins/` directory. 21 | 2. Activate GC Sermons through the 'Plugins' menu in WordPress. 22 | 23 | == Frequently Asked Questions == 24 | 25 | 26 | == Screenshots == 27 | 28 | 29 | == Changelog == 30 | 31 | = 0.1.0 = 32 | * First release 33 | 34 | == Upgrade Notice == 35 | 36 | = 0.1.0 = 37 | First Release 38 | -------------------------------------------------------------------------------- /includes/taxonomies/class-topic.php: -------------------------------------------------------------------------------- 1 | array( __( 'Topic', 'gc-sermons' ), __( 'Topics', 'gc-sermons' ), 'gcs-topic' ), 28 | 'args' => array( 29 | 'rewrite' => array( 'slug' => 'sermon-topic' ), 30 | ), 31 | ) ); 32 | } 33 | 34 | /** 35 | * Initiate our hooks 36 | * 37 | * @since 0.1.0 38 | * @return void 39 | */ 40 | public function hooks() { 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /includes/taxonomies/class-tag.php: -------------------------------------------------------------------------------- 1 | array( __( 'Tag', 'gc-sermons' ), __( 'Tags', 'gc-sermons' ), 'gcs-tag' ), 28 | 'args' => array( 29 | 'hierarchical' => false, 30 | 'rewrite' => array( 'slug' => 'sermon-tag' ), 31 | ), 32 | ) ); 33 | } 34 | 35 | /** 36 | * Initiate our hooks 37 | * 38 | * @since 0.1.0 39 | * @return void 40 | */ 41 | public function hooks() { 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-recent-speaker/class-run.php: -------------------------------------------------------------------------------- 1 | 0, // 'Blank, "recent", or "0" will play the most recent video. 24 | 'recent' => 'recent', // Options: 'recent', 'audio', 'video' 25 | 'remove_thumbnail' => false, 26 | 'thumbnail_size' => 'medium', 27 | ); 28 | 29 | /** 30 | * Shortcode Output 31 | */ 32 | public function shortcode() { 33 | $content = gc_get_sermon_speaker_info( $this->get_sermon(), ! $this->bool_att( 'remove_thumbnail' ) ); 34 | 35 | return $content; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Dockunit.json: -------------------------------------------------------------------------------- 1 | { 2 | "containers": [ 3 | { 4 | "prettyName": "PHP 5.2 FPM WordPress 4.1", 5 | "image": "dockunit/prebuilt-images:php-mysql-phpunit-5.2-fpm", 6 | "beforeScripts": [ 7 | "service mysql start", 8 | "bash bin/install-wp-tests.sh wordpress_test root '' localhost 4.1" 9 | ], 10 | "testCommand": "phpunit" 11 | }, 12 | { 13 | "prettyName": "PHP 5.6 FPM WordPress 4.0", 14 | "image": "dockunit/prebuilt-images:php-mysql-phpunit-5.6-fpm", 15 | "beforeScripts": [ 16 | "service mysql start", 17 | "bash bin/install-wp-tests.sh wordpress_test2 root '' localhost 4.0" 18 | ], 19 | "testCommand": "phpunit" 20 | }, 21 | { 22 | "prettyName": "PHP 7.0 RC-1", 23 | "image": "dockunit/prebuilt-images:php-mysql-phpunit-7.0-rc-1-fpm", 24 | "beforeScripts": [ 25 | "service mysql start", 26 | "bash bin/install-wp-tests.sh wordpress_test3 root '' localhost 3.9" 27 | ], 28 | "testCommand": "phpunit" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /assets/js/gc-sermons-admin.js: -------------------------------------------------------------------------------- 1 | window.GCSermonsAdmin = window.GCSermonsAdmin || {}; 2 | 3 | ( function( window, document, $, app, undefined ) { 4 | 'use strict'; 5 | 6 | var methodBackup = null; 7 | 8 | app.cache = function() { 9 | app.$ = {}; 10 | }; 11 | 12 | app.init = function() { 13 | app.cache(); 14 | 15 | $( document.body ) 16 | .on( 'keyup change', '.check-if-recent input[type="text"]', app.maybeToggle ) 17 | .on( 'shortcode_button:open', app.showNotRecent ); 18 | }; 19 | 20 | app.maybeToggle = function( evt ) { 21 | var $this = $( evt.target ); 22 | var value = $this.val(); 23 | if ( ! value || '0' === value || 0 === value || 'recent' === value ) { 24 | $this.parents( '.cmb2-metabox' ).find( '.hide-if-not-recent' ).show(); 25 | } else { 26 | $this.parents( '.cmb2-metabox' ).find( '.hide-if-not-recent' ).hide(); 27 | } 28 | }; 29 | 30 | app.showNotRecent = function() { 31 | $( '.scb-form-wrap .hide-if-not-recent' ).show(); 32 | }; 33 | 34 | $( app.init ); 35 | 36 | } )( window, document, jQuery, window.GCSermonsAdmin ); 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GC Sermons - BETA # 2 | **Contributors:** jtsternberg 3 | **Donate link:** http://dsgnwrks.pro 4 | **Tags:** 5 | **Requires at least:** 4.4 6 | **Tested up to:** 4.9.8 7 | **Stable tag:** 0.2.1 8 | **License:** GPLv2 9 | **License URI:** http://www.gnu.org/licenses/gpl-2.0.html 10 | 11 | ## Description ## 12 | 13 | Manage sermons and sermon content in WordPress. The [GC Staff](https://github.com/jtsternberg/GC-Staff) plugin is recommended to complement this plugin for church sites. 14 | 15 | **Please note:** you will need to run `composer install` in order to fetch the dependenceis for this plugin/library, **or** you can [download the zip here](https://github.com/jtsternberg/GC-Sermons/blob/master/gc-sermons.zip?raw=true). 16 | 17 | **Also please note:** This plugin is still in beta, and in active development, and _things may change_. If you have any questions, [let me know](http://twitter.com/jtsternberg). 18 | 19 | ### Documentation 20 | 21 | [Check out the wiki](https://github.com/jtsternberg/GC-Sermons/wiki) for usage. 22 | -------------------------------------------------------------------------------- /includes/taxonomies/class-scripture.php: -------------------------------------------------------------------------------- 1 | array( __( 'Scripture Reference', 'gc-sermons' ), __( 'Scripture References', 'gc-sermons' ), 'gcs-scripture' ), 32 | 'args' => array( 33 | 'rewrite' => array( 'slug' => 'scripture-reference' ), 34 | ), 35 | ) ); 36 | } 37 | 38 | /** 39 | * Initiate our hooks 40 | * 41 | * @since 0.1.3 42 | * @return void 43 | */ 44 | public function hooks() { 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-recent-series/class-run.php: -------------------------------------------------------------------------------- 1 | 0, // 'Blank, "recent", or "0" will play the most recent video. 24 | 'recent' => 'recent', // Options: 'recent', 'audio', 'video' 25 | 'remove_thumbnail' => true, 26 | 'thumbnail_size' => 'medium', 27 | 28 | // No admin 29 | 'remove_description' => true, 30 | 'wrap_classes' => '', 31 | ); 32 | 33 | /** 34 | * Shortcode Output 35 | */ 36 | public function shortcode() { 37 | $args = array(); 38 | foreach ( $this->atts_defaults as $key => $default_value ) { 39 | $args[ $key ] = is_bool( $this->atts_defaults[ $key ] ) 40 | ? $this->bool_att( $key, $default_value ) 41 | : $this->att( $key, $default_value ); 42 | } 43 | 44 | $args['wrap_classes'] .= ' gc-recent-series'; 45 | 46 | return gc_get_sermon_series_info( $this->get_sermon(), $args ); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /includes/class-async.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 32 | parent::__construct(); 33 | } 34 | 35 | /** 36 | * Prepare data for the asynchronous request 37 | * 38 | * @throws Exception If for any reason the request should not happen 39 | * 40 | * @param array $data An array of data sent to the hook 41 | * 42 | * @return array 43 | */ 44 | protected function prepare_data( $data ) { 45 | $object_id = $data[0]; 46 | $taxonomy = $data[3]; 47 | 48 | if ( $this->plugin->sermons->post_type() !== get_post_type( $object_id ) ) { 49 | throw new Exception( 'We only want async tasks for sermons' ); 50 | } 51 | 52 | return compact( 'object_id', 'taxonomy' ); 53 | } 54 | 55 | /** 56 | * Run the async task action 57 | */ 58 | protected function run_action() { 59 | if ( isset( $_POST['object_id'], $_POST['taxonomy'] ) ) { 60 | do_action( 'wp_async_set_sermon_terms', $_POST['object_id'], $_POST['taxonomy'] ); 61 | } 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### OSX ### 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear on external disk 14 | .Spotlight-V100 15 | .Trashes 16 | 17 | # Directories potentially created on remote AFP share 18 | .AppleDB 19 | .AppleDesktop 20 | Network Trash Folder 21 | Temporary Items 22 | .apdisk 23 | 24 | 25 | ### Bower ### 26 | bower_components 27 | .bower-cache 28 | .bower-registry 29 | .bower-tmp 30 | 31 | 32 | ### Node ### 33 | # Logs 34 | logs 35 | *.log 36 | 37 | # Runtime data 38 | pids 39 | *.pid 40 | *.seed 41 | 42 | # Directory for instrumented libs generated by jscoverage/JSCover 43 | lib-cov 44 | 45 | # Coverage directory used by tools like istanbul 46 | coverage 47 | 48 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 49 | .grunt 50 | 51 | # node-waf configuration 52 | .lock-wscript 53 | 54 | # Compiled binary addons (http://nodejs.org/api/addons.html) 55 | build/Release 56 | 57 | # Dependency directory 58 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 59 | node_modules 60 | 61 | 62 | ### Composer ### 63 | composer.phar 64 | /vendor 65 | 66 | 67 | # Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file 68 | # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file 69 | # composer.lock 70 | 71 | ### Sass ### 72 | .sass-cache 73 | 74 | dandelion.yml 75 | phploy.ini 76 | .revision -------------------------------------------------------------------------------- /includes/taxonomies/class-taxonomies.php: -------------------------------------------------------------------------------- 1 | series = new GCS_Series( $sermons ); 54 | $this->speaker = new GCS_Speaker( $sermons ); 55 | $this->topic = new GCS_Topic( $sermons ); 56 | $this->tag = new GCS_Tag( $sermons ); 57 | $this->scripture = new GCS_Scripture( $sermons ); 58 | } 59 | 60 | /** 61 | * Magic getter for our object. Allows getting but not setting. 62 | * 63 | * @param string $field 64 | * @throws Exception Throws an exception if the field is invalid. 65 | * @return mixed 66 | */ 67 | public function __get( $field ) { 68 | switch ( $field ) { 69 | case 'series': 70 | case 'speaker': 71 | case 'topic': 72 | case 'tag': 73 | case 'scripture': 74 | return $this->{$field}; 75 | default: 76 | throw new Exception( 'Invalid ' . __CLASS__ . ' property: ' . $field ); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /templates/searchform.php: -------------------------------------------------------------------------------- 1 | 24 | -------------------------------------------------------------------------------- /templates/searchform-xhtml.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /includes/shortcodes/class-shortcodes-recent-admin-base.php: -------------------------------------------------------------------------------- 1 | shortcode}", array( $this, 'enqueue_js' ) ); 22 | 23 | // Do this super late. 24 | add_filter( "{$this->shortcode}_shortcode_fields", array( $this, 'maybe_remove_recent_attribute' ), 100000 ); 25 | } 26 | 27 | public function enqueue_js() { 28 | wp_enqueue_script( 29 | 'gc-sermons-admin', 30 | GC_Sermons_Plugin::$url . 'assets/js/gc-sermons-admin.js', 31 | array( 'jquery' ), 32 | GC_Sermons_Plugin::VERSION, 33 | true 34 | ); 35 | } 36 | 37 | /** 38 | * Removes 'recent' shortcode attribute when it isn't applicable. 39 | * 40 | * @since 0.1.3 41 | * 42 | * @param array $updated Array of shortcode attributes. 43 | * 44 | * @return array Modified array of shortcode attributes. 45 | */ 46 | public function maybe_remove_recent_attribute( $updated ) { 47 | 48 | // If recent is set, but shouldn't be, let's remove it. 49 | if ( isset( $updated['recent'], $updated['sermon_id'] ) ) { 50 | if ( $updated['sermon_id'] && '0' !== $updated['sermon_id'] && 0 !== $updated['sermon_id'] && 'recent' !== $updated['sermon_id'] ) { 51 | unset( $updated['recent'] ); 52 | } 53 | } 54 | 55 | return $updated; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /includes/shortcodes/class-shortcodes-admin-base.php: -------------------------------------------------------------------------------- 1 | run = $run; 34 | 35 | parent::__construct( 36 | $this->run->shortcode, 37 | GC_Sermons_Plugin::VERSION, 38 | $this->run->atts_defaults 39 | ); 40 | 41 | // Do this super late. 42 | add_filter( "{$this->shortcode}_shortcode_fields", array( $this, 'maybe_remove_prefixes' ), 99999 ); 43 | } 44 | 45 | /** 46 | * If the shortcode has a prefix property, we remove it from the shortcode attributes. 47 | * 48 | * @since 0.1.3 49 | * 50 | * @param array $updated Array of shortcode attributes. 51 | * 52 | * @return array Modified array of shortcode attributes. 53 | */ 54 | public function maybe_remove_prefixes( $updated ) { 55 | if ( $this->prefix ) { 56 | $prefix_length = strlen( $this->prefix ); 57 | $new_updated = array(); 58 | 59 | foreach ( $updated as $key => $value) { 60 | 61 | if ( $this->prefix === substr( $key, 0, $prefix_length ) ) { 62 | $key = substr( $key, $prefix_length ); 63 | } 64 | 65 | $new_updated[ $key ] = $value; 66 | } 67 | 68 | $updated = $new_updated; 69 | } 70 | 71 | return $updated; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /assets/js/gc-sermon-videos.js: -------------------------------------------------------------------------------- 1 | window.GCVideoModal = window.GCVideoModal || {}; 2 | 3 | /** 4 | * @todo Play video when opening 5 | * @todo Test with local video 6 | * @todo Add a close icon 7 | */ 8 | ( function( window, document, $, app, undefined ) { 9 | 'use strict'; 10 | 11 | app.cache = function() { 12 | app.$ = {}; 13 | app.$.overlay = $( document.getElementById( 'gc-video-overlay' ) ); 14 | app.$.body = $( document.body ); 15 | app.$.modals = $( '.gc-sermons-modal' ); 16 | }; 17 | 18 | app.init = function() { 19 | app.cache(); 20 | if ( 'function' === typeof $.fn.prettyPhoto ) { 21 | $( '.gc-sermons-play-button' ).prettyPhoto({ 22 | default_width : 1100, 23 | default_height : 619, 24 | theme : 'dark_square', 25 | }); 26 | 27 | return; 28 | } 29 | 30 | $( document ).on( 'keydown', function( evt ) { 31 | var escapeKey = 27; 32 | if ( escapeKey === evt.keyCode ) { 33 | evt.preventDefault(); 34 | app.closeModals(); 35 | } 36 | } ); 37 | 38 | app.$.body 39 | .on( 'click', '.gc-sermons-play-button', app.clickOpenModal ) 40 | .on( 'click', '#gc-video-overlay', app.closeModals ); 41 | }; 42 | 43 | app.clickOpenModal = function( evt ) { 44 | evt.preventDefault(); 45 | var sermonId = $( this ).data( 'sermonid' ); 46 | 47 | app.showVideo( sermonId ); 48 | }; 49 | 50 | app.showVideo = function( sermonId ) { 51 | app.$.overlay.fadeIn( 'fast' ); 52 | 53 | var $video = app.$.modals.filter( '#gc-sermons-video-'+ sermonId ).removeClass( 'gcinvisible' ); 54 | 55 | $video.find( '.gc-sermons-video-container' ).html( $video.find( '.tmpl-videoModal' ).html() ).fitVids(); 56 | 57 | $video.css({ 'margin-top' : - Math.floor( parseInt( $video.outerHeight() * 0.6 ) ) }); 58 | }; 59 | 60 | app.closeModals = function() { 61 | app.$.overlay.fadeOut(); 62 | app.$.modals.addClass( 'gcinvisible' ).find( '.gc-sermons-video-container' ).empty(); 63 | }; 64 | 65 | $( app.init ); 66 | 67 | } )( window, document, jQuery, window.GCVideoModal ); 68 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jtsternberg/gc-sermons", 3 | "type": "wordpress-plugin", 4 | "description": "Manage sermons and sermon content in WordPress", 5 | "keywords": ["wordpress", "plugin", "generator-plugin-wp", "sermons"], 6 | "homepage": "https://github.com/jtsternberg/GC-Sermons", 7 | "license": "GPL-2.0-or-later", 8 | "authors": [ 9 | { 10 | "name": "jtsternberg", 11 | "email": "justin@dsgnwrks.pro", 12 | "homepage": "http://dsgnwrks.pro", 13 | "role": "Developer" 14 | } 15 | ], 16 | "minimum-stability": "dev", 17 | "autoload": { 18 | "classmap": [ 19 | "gc-sermons.php", 20 | "includes/", 21 | "vendor/webdevstudios/cpt-core/CPT_Core.php", 22 | "vendor/webdevstudios/taxonomy_core/Taxonomy_Core.php" 23 | ], 24 | "files": [ 25 | "vendor/webdevstudios/cmb2-user-select/cmb2-user-select.php", 26 | "vendor/webdevstudios/cmb2-post-search-field/cmb2_post_search_field.php", 27 | "vendor/jtsternberg/cmb2-related-links/cmb2-related-links.php", 28 | "vendor/jtsternberg/cmb2-term-select/cmb2-term-select.php", 29 | "vendor/webdevstudios/wds-shortcodes/wds-shortcodes.php", 30 | "vendor/tgmpa/tgm-plugin-activation/class-tgm-plugin-activation.php" 31 | ] 32 | }, 33 | "require": { 34 | "php": ">=5.2", 35 | "xrstf/composer-php52": "1.*", 36 | "techcrunch/wp-async-task": "dev-master", 37 | "tgmpa/tgm-plugin-activation": "^2.5.2", 38 | "webdevstudios/cpt-core": "dev-master", 39 | "webdevstudios/taxonomy_core": "^0.2.4", 40 | "webdevstudios/cmb2-post-search-field": "^v0.2.5", 41 | "jtsternberg/cmb2-related-links": "^v0.1.1", 42 | "jtsternberg/cmb2-term-select": "^v0.1.0", 43 | "webdevstudios/wds-shortcodes": "^v1.0.7", 44 | "webdevstudios/cmb2-user-select": "^v0.2.0" 45 | }, 46 | "scripts": { 47 | "post-install-cmd": [ 48 | "xrstf\\Composer52\\Generator::onPostInstallCmd" 49 | ], 50 | "post-update-cmd": [ 51 | "xrstf\\Composer52\\Generator::onPostInstallCmd" 52 | ], 53 | "post-autoload-dump": [ 54 | "xrstf\\Composer52\\Generator::onPostInstallCmd" 55 | ] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /includes/taxonomies/class-series.php: -------------------------------------------------------------------------------- 1 | 'medium', 33 | ); 34 | 35 | /** 36 | * Constructor 37 | * Register Taxonomy. See documentation in Taxonomy_Core, and in wp-includes/taxonomy.php 38 | * 39 | * @since 0.1.0 40 | * @param object $sermons GCS_Sermons object. 41 | * @return void 42 | */ 43 | public function __construct( $sermons ) { 44 | parent::__construct( $sermons, array( 45 | 'labels' => array( __( 'Sermon Series', 'gc-sermons' ), __( 'Sermon Series', 'gc-sermons' ), 'gc-sermon-series' ), 46 | 'args' => array( 47 | 'hierarchical' => false, 48 | 'show_admin_column' => false, 49 | 'rewrite' => array( 'slug' => 'sermon-series' ), 50 | ), 51 | ) ); 52 | } 53 | 54 | /** 55 | * Initiate our hooks 56 | * 57 | * @since 0.1.0 58 | * @return void 59 | */ 60 | public function hooks() { 61 | add_action( 'cmb2_admin_init', array( $this, 'fields' ) ); 62 | } 63 | 64 | /** 65 | * Add custom fields to the CPT 66 | * 67 | * @since 0.1.0 68 | * @return void 69 | */ 70 | public function fields() { 71 | $cmb = $this->new_cmb2( array( 72 | 'id' => 'gc_sermon_series_metabox', 73 | 'taxonomies' => array( $this->taxonomy() ), 74 | 'object_types' => array( 'term' ), 75 | 'fields' => array( 76 | $this->image_meta_key => array( 77 | 'name' => __( 'Sermon Series Image', 'gc-sermons' ), 78 | 'desc' => __( 'Select the series\' branding image', 'gc-sermons' ), 79 | 'id' => $this->image_meta_key, 80 | 'type' => 'file' 81 | ), 82 | ), 83 | ) ); 84 | 85 | $this->add_image_column( __( 'Series Image', 'gc-sermons' ) ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /includes/shortcodes/class-shortcodes-run-base.php: -------------------------------------------------------------------------------- 1 | sermons = $sermons; 27 | parent::__construct(); 28 | } 29 | 30 | protected function get_sermon() { 31 | $sermon_id = $this->att( 'sermon_id' ); 32 | 33 | if ( ! $sermon_id || 'recent' === $sermon_id || '0' === $sermon_id || 0 === $sermon_id ) { 34 | 35 | $this->shortcode_object->set_att( 'sermon', $this->most_recent_sermon() ); 36 | 37 | } elseif ( 'this' === $sermon_id ) { 38 | 39 | $this->shortcode_object->set_att( 'sermon', gc_get_sermon_post( get_queried_object_id() ) ); 40 | 41 | } elseif ( is_numeric( $sermon_id ) ) { 42 | 43 | $this->shortcode_object->set_att( 'sermon', gc_get_sermon_post( $sermon_id ) ); 44 | 45 | } 46 | 47 | return $this->att( 'sermon' ); 48 | } 49 | 50 | protected function most_recent_sermon() { 51 | switch ( $this->att( 'recent', 'recent' ) ) { 52 | case 'audio': 53 | return $this->sermons->most_recent_with_audio(); 54 | 55 | case 'video': 56 | return $this->sermons->most_recent_with_video(); 57 | } 58 | 59 | return $this->sermons->most_recent(); 60 | } 61 | 62 | public function get_inline_styles() { 63 | $style = ''; 64 | $has_icon_font_size = false; 65 | 66 | if ( $this->att( 'icon_color' ) || $this->att( 'icon_size' ) ) { 67 | $style = ' style="'; 68 | // Get/check our text_color attribute 69 | if ( $this->att( 'icon_color' ) ) { 70 | $text_color = sanitize_text_field( $this->att( 'icon_color' ) ); 71 | $style .= 'color: ' . $text_color .';'; 72 | } 73 | if ( is_numeric( $this->att( 'icon_size' ) ) ) { 74 | $has_icon_font_size = absint( $this->att( 'icon_size' ) ); 75 | $style .= 'font-size: ' . $has_icon_font_size .'em;'; 76 | } 77 | $style .= '"'; 78 | } 79 | 80 | return array( $style, $has_icon_font_size ); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-play-button/class-admin.php: -------------------------------------------------------------------------------- 1 | __( 'GC Sermon Play', 'gc-sermons' ), 26 | 'button_tooltip' => __( 'GC Sermon Play Button', 'gc-sermons' ), 27 | 'icon' => 'dashicons-controls-play', 28 | 'mceView' => true, // The future 29 | ); 30 | } 31 | 32 | /** 33 | * Adds fields to the button modal using CMB2 34 | * 35 | * @param $fields 36 | * @param $button_data 37 | * 38 | * @return array 39 | */ 40 | function fields( $fields, $button_data ) { 41 | $fields[] = array( 42 | 'name' => __( 'Sermon to play', 'gc-sermons' ), 43 | 'desc' => __( 'Blank, "recent", or "0" will play the most recent video. Otherwise enter a post ID. Click the magnifying glass to search for a Sermon post.', 'gc-sermons' ), 44 | 'id' => $this->prefix . 'sermon_id', 45 | 'type' => 'post_search_text', 46 | 'post_type' => $this->run->sermons->post_type(), 47 | 'select_type' => 'radio', 48 | 'select_behavior' => 'replace', 49 | ); 50 | 51 | $fields[] = array( 52 | 'name' => __( 'Icon Color', 'gc-sermons' ), 53 | 'type' => 'colorpicker', 54 | 'id' => $this->prefix . 'icon_color', 55 | 'default' => $this->atts_defaults['icon_color'], 56 | ); 57 | 58 | $fields[] = array( 59 | 'name' => __( 'Icon Size', 'gc-sermons' ), 60 | 'desc' => __( 'Select a font-size (in ems, or enter either "medium", "large", or "small".', 'gc-sermons' ), 61 | 'type' => 'text', 62 | 'id' => $this->prefix . 'icon_size', 63 | 'default' => $this->atts_defaults['icon_size'], 64 | ); 65 | 66 | $fields[] = array( 67 | 'name' => __( 'Extra CSS Classes', 'gc-sermons' ), 68 | 'desc' => __( 'Enter classes separated by spaces (e.g. "class1 class2")', 'gc-sermons' ), 69 | 'type' => 'text', 70 | 'id' => $this->prefix . 'icon_class', 71 | 'default' => $this->atts_defaults['icon_class'], 72 | ); 73 | 74 | return $fields; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-recent-speaker/class-admin.php: -------------------------------------------------------------------------------- 1 | __( 'GC Recent Speaker', 'gc-sermons' ), 26 | 'button_tooltip' => __( 'GC Recent Speaker', 'gc-sermons' ), 27 | 'icon' => 'dashicons-businessman', 28 | // 'mceView' => true, // The future 29 | ); 30 | } 31 | 32 | /** 33 | * Adds fields to the button modal using CMB2 34 | * 35 | * @param $fields 36 | * @param $button_data 37 | * 38 | * @return array 39 | */ 40 | function fields( $fields, $button_data ) { 41 | 42 | $fields[] = array( 43 | 'name' => __( 'Sermon ID', 'gc-sermons' ), 44 | 'desc' => __( 'Blank, "recent", or "0" will get the most recent sermon\'s speaker info. Otherwise enter a post ID. Click the magnifying glass to search for a Sermon post.', 'gc-sermons' ), 45 | 'id' => $this->prefix . 'sermon_id', 46 | 'type' => 'post_search_text', 47 | 'post_type' => $this->run->sermons->post_type(), 48 | 'select_type' => 'radio', 49 | 'select_behavior' => 'replace', 50 | 'row_classes' => 'check-if-recent', 51 | ); 52 | 53 | $fields[] = array( 54 | 'name' => __( 'Filter Most Recent Sermon By:', 'gc-sermons' ), 55 | 'desc' => __( 'If setting "Sermon ID" above to blank, "recent", or "0", this setting determines which type of most recent sermon to get the speaker info for.', 'gc-sermons' ), 56 | 'type' => 'select', 57 | 'id' => $this->prefix . 'recent', 58 | 'default' => $this->atts_defaults['recent'], 59 | 'row_classes' => 'hide-if-not-recent', 60 | 'options' => array( 61 | 'recent' => __( 'Most Recent', 'gc-sermons' ), 62 | 'audio' => __( 'Most Recent with Audio', 'gc-sermons' ), 63 | 'video' => __( 'Most Recent with Video', 'gc-sermons' ), 64 | ), 65 | ); 66 | 67 | $fields[] = array( 68 | 'name' => __( 'Remove Thumbnail', 'gc-sermons' ), 69 | 'type' => 'checkbox', 70 | 'id' => $this->prefix . 'remove_thumbnail', 71 | 'default' => false, 72 | ); 73 | 74 | $fields[] = array( 75 | 'name' => __( 'Thumbnail Size (if included)', 'gc-sermons' ), 76 | 'type' => 'text', 77 | 'id' => $this->prefix . 'thumbnail_size', 78 | 'default' => $this->atts_defaults['thumbnail_size'], 79 | ); 80 | 81 | 82 | return $fields; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /includes/shortcodes/class-shortcodes.php: -------------------------------------------------------------------------------- 1 | play_button = new GCS_Shortcodes_Play_Button( $plugin ); 83 | $this->sermons = new GCS_Shortcodes_Sermons( $plugin ); 84 | $this->recent_series = new GCS_Shortcodes_Recent_Series( $plugin ); 85 | $this->recent_speaker = new GCS_Shortcodes_Recent_Speaker( $plugin ); 86 | $this->series = new GCS_Shortcodes_Series( $plugin ); 87 | $this->related_links = new GCS_Shortcodes_Related_Links( $plugin ); 88 | $this->video_player = new GCS_Shortcodes_Video_Player( $plugin ); 89 | $this->audio_player = new GCS_Shortcodes_Audio_Player( $plugin ); 90 | $this->search = new GCS_Shortcodes_Sermon_Search( $plugin ); 91 | } 92 | 93 | /** 94 | * Magic getter for our object. Allows getting but not setting. 95 | * 96 | * @param string $field 97 | * @throws Exception Throws an exception if the field is invalid. 98 | * @return mixed 99 | */ 100 | public function __get( $field ) { 101 | return $this->{$field}; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-recent-series/class-admin.php: -------------------------------------------------------------------------------- 1 | __( 'GC Recent Series', 'gc-sermons' ), 26 | 'button_tooltip' => __( 'GC Recent Series', 'gc-sermons' ), 27 | 'icon' => 'dashicons-images-alt', 28 | // 'mceView' => true, // The future 29 | ); 30 | } 31 | 32 | /** 33 | * Adds fields to the button modal using CMB2 34 | * 35 | * @param $fields 36 | * @param $button_data 37 | * 38 | * @return array 39 | */ 40 | function fields( $fields, $button_data ) { 41 | 42 | $fields[] = array( 43 | 'name' => __( 'Sermon ID', 'gc-sermons' ), 44 | 'desc' => __( 'Blank, "recent", or "0" will get the most recent sermon\'s series info. Otherwise enter a post ID. Click the magnifying glass to search for a Sermon post.', 'gc-sermons' ), 45 | 'id' => $this->prefix . 'sermon_id', 46 | 'type' => 'post_search_text', 47 | 'post_type' => $this->run->sermons->post_type(), 48 | 'select_type' => 'radio', 49 | 'select_behavior' => 'replace', 50 | 'row_classes' => 'check-if-recent', 51 | ); 52 | 53 | $fields[] = array( 54 | 'name' => __( 'Filter Most Recent Sermon By:', 'gc-sermons' ), 55 | 'desc' => __( 'If setting "Sermon ID" above to blank, "recent", or "0", this setting determines which type of most recent sermon to get the series info for.', 'gc-sermons' ), 56 | 'type' => 'select', 57 | 'id' => $this->prefix . 'recent', 58 | 'default' => $this->atts_defaults['recent'], 59 | 'row_classes' => 'hide-if-not-recent', 60 | 'options' => array( 61 | 'recent' => __( 'Most Recent', 'gc-sermons' ), 62 | 'audio' => __( 'Most Recent with Audio', 'gc-sermons' ), 63 | 'video' => __( 'Most Recent with Video', 'gc-sermons' ), 64 | ), 65 | ); 66 | 67 | $fields[] = array( 68 | 'name' => __( 'Remove Thumbnail', 'gc-sermons' ), 69 | 'type' => 'checkbox', 70 | 'id' => $this->prefix . 'remove_thumbnail', 71 | 'default' => false, 72 | ); 73 | 74 | $fields[] = array( 75 | 'name' => __( 'Thumbnail Size (if included)', 'gc-sermons' ), 76 | 'type' => 'text', 77 | 'id' => $this->prefix . 'thumbnail_size', 78 | 'default' => $this->atts_defaults['thumbnail_size'], 79 | ); 80 | 81 | return $fields; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-search/class-sermons-search-run.php: -------------------------------------------------------------------------------- 1 | search_query = $search_query; 49 | $this->current_page = absint( gc__get_arg( 'results-page', 1 ) ); 50 | 51 | parent::__construct( $sermons, $taxonomies ); 52 | } 53 | 54 | public function get_search_results( $atts = array(), $content = '' ) { 55 | add_filter( 'gcs_get_sermons_args', array( $this, 'filter_sermon_args' ) ); 56 | 57 | $this->results = parent::shortcode_callback( $atts, $content ); 58 | 59 | remove_filter( 'gcs_get_sermons_args', array( $this, 'filter_sermon_args' ) ); 60 | 61 | return $this->results; 62 | } 63 | 64 | public function filter_sermon_args( $args ) { 65 | $args['s'] = sanitize_text_field( $this->search_query ); 66 | return $args; 67 | } 68 | 69 | /** 70 | * Make this method applicable. 71 | * 72 | * @since [since] 73 | * 74 | * @return [type] [description] 75 | */ 76 | public function get_initial_query_args() { 77 | $posts_per_page = (int) $this->att( 'per_page', get_option( 'posts_per_page' ) ); 78 | $paged = $this->current_page; 79 | $offset = ( ( $paged - 1 ) * $posts_per_page ) + $this->att( 'list_offset', 0 ); 80 | 81 | return compact( 'posts_per_page', 'paged', 'offset' ); 82 | } 83 | 84 | protected function get_pagination( $total_pages ) { 85 | $this->total_pages = $total_pages; 86 | $nav = array( 'prev_link' => '', 'next_link' => '' ); 87 | 88 | if ( ! $this->bool_att( 'remove_pagination' ) ) { 89 | $nav['prev_link'] = gc_search_get_previous_results_link(); 90 | $nav['next_link'] = gc_search_get_next_results_link( $total_pages ); 91 | } 92 | 93 | return $nav; 94 | } 95 | 96 | protected function get_wrap_classes() { 97 | return parent::get_wrap_classes() . ' gc-sermons-search-wrap'; 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-audio-player/class-shortcode.php: -------------------------------------------------------------------------------- 1 | run = new GCS_Shortcodes_Audio_Player_Run( $plugin->sermons ); 18 | $this->admin = new GCS_Shortcodes_Audio_Player_Admin( $this->run ); 19 | 20 | parent::hooks(); 21 | } 22 | 23 | } 24 | 25 | /** 26 | * GC Sermons Audio Player Shortcode 27 | * 28 | * @version 0.1.3 29 | * @package GC Sermons 30 | */ 31 | class GCS_Shortcodes_Audio_Player_Run extends GCS_Shortcodes_Run_Base { 32 | 33 | /** 34 | * The Shortcode Tag 35 | * @var string 36 | * @since 0.1.0 37 | */ 38 | public $shortcode = 'gc_audio_player'; 39 | 40 | /** 41 | * Default attributes applied to the shortcode. 42 | * @var array 43 | * @since 0.1.0 44 | */ 45 | public $atts_defaults = array( 46 | 'sermon_id' => 0, // 'Blank, "recent", or "0" will play the most recent audio. 47 | ); 48 | 49 | /** 50 | * Shortcode Output 51 | */ 52 | public function shortcode() { 53 | return gc_get_sermon_audio_player( $this->get_sermon() ); 54 | } 55 | 56 | } 57 | 58 | 59 | /** 60 | * GC Sermons Audio Player Shortcode - Admin 61 | * @version 0.1.3 62 | * @package GC Sermons 63 | */ 64 | class GCS_Shortcodes_Audio_Player_Admin extends GCSS_Recent_Admin_Base { 65 | 66 | /** 67 | * Shortcode prefix for field ids. 68 | * 69 | * @var string 70 | * @since 0.1.3 71 | */ 72 | protected $prefix = 'gc_audplayer_'; 73 | 74 | /** 75 | * Sets up the button 76 | * 77 | * @return array 78 | */ 79 | function js_button_data() { 80 | return array( 81 | 'qt_button_text' => __( 'GC Sermon Audio Player', 'gc-sermons' ), 82 | 'button_tooltip' => __( 'GC Sermon Audio Player', 'gc-sermons' ), 83 | 'icon' => 'dashicons-format-audio', 84 | // 'mceView' => true, // The future 85 | ); 86 | } 87 | 88 | /** 89 | * Adds fields to the button modal using CMB2 90 | * 91 | * @param $fields 92 | * @param $button_data 93 | * 94 | * @return array 95 | */ 96 | function fields( $fields, $button_data ) { 97 | 98 | $fields[] = array( 99 | 'name' => __( 'Sermon ID', 'gc-sermons' ), 100 | 'desc' => __( 'Blank, "recent", or "0" will get the most recent sermon\'s audio player. Otherwise enter a post ID. Click the magnifying glass to search for a Sermon post.', 'gc-sermons' ), 101 | 'id' => $this->prefix . 'sermon_id', 102 | 'type' => 'post_search_text', 103 | 'post_type' => $this->run->sermons->post_type(), 104 | 'select_type' => 'radio', 105 | 'select_behavior' => 'replace', 106 | 'row_classes' => 'check-if-recent', 107 | ); 108 | 109 | return $fields; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-video-player/class-shortcode.php: -------------------------------------------------------------------------------- 1 | run = new GCS_Shortcodes_Video_Player_Run( $plugin->sermons ); 19 | $this->admin = new GCS_Shortcodes_Video_Player_Admin( $this->run ); 20 | 21 | parent::hooks(); 22 | } 23 | 24 | } 25 | 26 | /** 27 | * GC Sermons Video Player Shortcode 28 | * 29 | * @version 0.1.3 30 | * @package GC Sermons 31 | */ 32 | class GCS_Shortcodes_Video_Player_Run extends GCS_Shortcodes_Run_Base { 33 | 34 | /** 35 | * The Shortcode Tag 36 | * @var string 37 | * @since 0.1.0 38 | */ 39 | public $shortcode = 'gc_video_player'; 40 | 41 | /** 42 | * Default attributes applied to the shortcode. 43 | * @var array 44 | * @since 0.1.0 45 | */ 46 | public $atts_defaults = array( 47 | 'sermon_id' => 0, // 'Blank, "recent", or "0" will play the most recent video. 48 | ); 49 | 50 | /** 51 | * Shortcode Output 52 | */ 53 | public function shortcode() { 54 | return gc_get_sermon_video_player( $this->get_sermon() ); 55 | } 56 | 57 | } 58 | 59 | /** 60 | * GC Sermons Video Player Shortcode - Admin 61 | * @version 0.1.3 62 | * @package GC Sermons 63 | */ 64 | class GCS_Shortcodes_Video_Player_Admin extends GCSS_Recent_Admin_Base { 65 | 66 | /** 67 | * Shortcode prefix for field ids. 68 | * 69 | * @var string 70 | * @since 0.1.3 71 | */ 72 | protected $prefix = 'gc_vidplayer_'; 73 | 74 | /** 75 | * Sets up the button 76 | * 77 | * @return array 78 | */ 79 | function js_button_data() { 80 | return array( 81 | 'qt_button_text' => __( 'GC Sermon Video Player', 'gc-sermons' ), 82 | 'button_tooltip' => __( 'GC Sermon Video Player', 'gc-sermons' ), 83 | 'icon' => 'dashicons-format-video', 84 | // 'mceView' => true, // The future 85 | ); 86 | } 87 | 88 | /** 89 | * Adds fields to the button modal using CMB2 90 | * 91 | * @param $fields 92 | * @param $button_data 93 | * 94 | * @return array 95 | */ 96 | function fields( $fields, $button_data ) { 97 | 98 | $fields[] = array( 99 | 'name' => __( 'Sermon ID', 'gc-sermons' ), 100 | 'desc' => __( 'Blank, "recent", or "0" will get the most recent sermon\'s video player. Otherwise enter a post ID. Click the magnifying glass to search for a Sermon post.', 'gc-sermons' ), 101 | 'id' => $this->prefix . 'sermon_id', 102 | 'type' => 'post_search_text', 103 | 'post_type' => $this->run->sermons->post_type(), 104 | 'select_type' => 'radio', 105 | 'select_behavior' => 'replace', 106 | 'row_classes' => 'check-if-recent', 107 | ); 108 | 109 | return $fields; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /includes/post-types/class-post-types-base.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 37 | 38 | // Register this cpt 39 | // First parameter should be an array with Singular, Plural, and Registered name. 40 | parent::__construct( 41 | $args['labels'], 42 | $args['args'] 43 | ); 44 | 45 | $this->hooks(); 46 | add_action( 'plugins_loaded', array( $this, 'filter_values' ), 4 ); 47 | } 48 | 49 | public function filter_values() { 50 | if ( $this->overrides_processed ) { 51 | return; 52 | } 53 | 54 | $args = array( 55 | 'singular' => $this->singular, 56 | 'plural' => $this->plural, 57 | 'post_type' => $this->post_type, 58 | 'arg_overrides' => $this->arg_overrides, 59 | ); 60 | 61 | $filtered_args = apply_filters( 'gcs_post_types_'. $this->id, $args, $this ); 62 | 63 | if ( $filtered_args !== $args ) { 64 | foreach ( $args as $arg => $val ) { 65 | if ( isset( $filtered_args[ $arg ] ) ) { 66 | $this->{$arg} = $filtered_args[ $arg ]; 67 | } 68 | } 69 | } 70 | 71 | $this->overrides_processed = true; 72 | } 73 | 74 | /** 75 | * Provides access to protected class properties. 76 | * @since 0.2.0 77 | * @param boolean $key Specific CPT parameter to return 78 | * @return mixed Specific CPT parameter or array of singular, plural and registered name 79 | */ 80 | public function post_type( $key = 'post_type' ) { 81 | if ( ! $this->overrides_processed ) { 82 | $this->filter_values(); 83 | } 84 | 85 | return parent::post_type( $key ); 86 | } 87 | 88 | /** 89 | * Initiate our hooks 90 | * 91 | * @since 0.1.0 92 | * @return void 93 | */ 94 | abstract function hooks(); 95 | 96 | /** 97 | * Wrapper for new_cmb2_box 98 | * 99 | * @since 0.1.1 100 | * 101 | * @param array $args Array of CMB2 args 102 | * 103 | * @return CMB2 104 | */ 105 | public function new_cmb2( $args ) { 106 | $cmb_id = $args['id']; 107 | return new_cmb2_box( apply_filters( "gcs_cmb2_box_args_{$this->id}_{$cmb_id}", $args ) ); 108 | } 109 | 110 | /** 111 | * Magic getter for our object. Allows getting but not setting. 112 | * 113 | * @param string $field 114 | * @throws Exception Throws an exception if the field is invalid. 115 | * @return mixed 116 | */ 117 | public function __get( $field ) { 118 | switch ( $field ) { 119 | case 'id': 120 | case 'arg_overrides': 121 | case 'cpt_args': 122 | return $this->{$field}; 123 | default: 124 | throw new Exception( 'Invalid ' . __CLASS__ . ' property: ' . $field ); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-series/class-admin.php: -------------------------------------------------------------------------------- 1 | __( 'GC Series', 'gc-sermons' ), 26 | 'button_tooltip' => __( 'GC Series', 'gc-sermons' ), 27 | 'icon' => 'dashicons-images-alt', 28 | // 'mceView' => true, // The future 29 | ); 30 | } 31 | 32 | /** 33 | * Adds fields to the button modal using CMB2 34 | * 35 | * @param $fields 36 | * @param $button_data 37 | * 38 | * @return array 39 | */ 40 | function fields( $fields, $button_data ) { 41 | 42 | $fields[] = array( 43 | 'name' => __( 'Number of Series to Show Per-Page', 'gc-sermons' ), 44 | 'type' => 'text_small', 45 | 'id' => $this->prefix . 'per_page', 46 | 'default' => get_option( 'posts_per_page', $this->atts_defaults['per_page'] ), 47 | ); 48 | 49 | $fields[] = array( 50 | 'name' => __( 'Remove Year Date Separators', 'gc-sermons' ), 51 | 'type' => 'checkbox', 52 | 'id' => $this->prefix . 'remove_dates', 53 | 'default' => false, 54 | ); 55 | 56 | $fields[] = array( 57 | 'name' => __( 'Remove Pagination', 'gc-sermons' ), 58 | 'type' => 'checkbox', 59 | 'id' => $this->prefix . 'remove_pagination', 60 | 'default' => false, 61 | ); 62 | 63 | $fields[] = array( 64 | 'name' => __( 'Remove Thumbnail', 'gc-sermons' ), 65 | 'type' => 'checkbox', 66 | 'id' => $this->prefix . 'remove_thumbnail', 67 | 'default' => false, 68 | ); 69 | 70 | $fields[] = array( 71 | 'name' => __( 'Thumbnail Size (if included)', 'gc-sermons' ), 72 | 'type' => 'text', 73 | 'id' => $this->prefix . 'thumbnail_size', 74 | 'default' => $this->atts_defaults['thumbnail_size'], 75 | ); 76 | 77 | $fields[] = array( 78 | 'name' => __( 'Max number of columns', 'gc-sermons' ), 79 | 'desc' => __( 'Will vary on device screen width', 'gc-sermons' ), 80 | 'type' => 'radio_inline', 81 | 'options' => array( 1 => 1, 2 => 2, 3 => 3, 4 => 4 ), 82 | 'id' => $this->prefix . 'number_columns', 83 | 'default' => $this->atts_defaults['number_columns'], 84 | ); 85 | 86 | $fields[] = array( 87 | 'name' => __( 'Offset', 'gc-sermons' ), 88 | 'desc' => __( 'Changes which series starts the list', 'gc-sermons' ), 89 | 'type' => 'text_small', 90 | 'id' => $this->prefix . 'list_offset', 91 | 'sanitization_cb' => 'absint', 92 | 'default' => $this->atts_defaults['list_offset'], 93 | ); 94 | 95 | $fields[] = array( 96 | 'name' => __( 'Extra Wrap CSS Classes', 'gc-sermons' ), 97 | 'desc' => __( 'Enter classes separated by spaces (e.g. "class1 class2")', 'gc-sermons' ), 98 | 'type' => 'text', 99 | 'id' => $this->prefix . 'wrap_classes', 100 | 'default' => $this->atts_defaults['wrap_classes'], 101 | ); 102 | 103 | return $fields; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /assets/js/vendor/jquery.fitvids.js: -------------------------------------------------------------------------------- 1 | /*jshint browser:true */ 2 | /*! 3 | * FitVids 1.1 4 | * 5 | * Copyright 2013, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com 6 | * Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/ 7 | * Released under the WTFPL license - http://sam.zoy.org/wtfpl/ 8 | * 9 | */ 10 | 11 | ;(function( $ ){ 12 | 13 | 'use strict'; 14 | 15 | $.fn.fitVids = function( options ) { 16 | var settings = { 17 | customSelector: null, 18 | ignore: null 19 | }; 20 | 21 | if(!document.getElementById('fit-vids-style')) { 22 | // appendStyles: https://github.com/toddmotto/fluidvids/blob/master/dist/fluidvids.js 23 | var head = document.head || document.getElementsByTagName('head')[0]; 24 | var css = '.fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}'; 25 | var div = document.createElement("div"); 26 | div.innerHTML = '

    x

    '; 27 | head.appendChild(div.childNodes[1]); 28 | } 29 | 30 | if ( options ) { 31 | $.extend( settings, options ); 32 | } 33 | 34 | return this.each(function(){ 35 | var selectors = [ 36 | 'iframe[src*="player.vimeo.com"]', 37 | 'iframe[src*="youtube.com"]', 38 | 'iframe[src*="youtube-nocookie.com"]', 39 | 'iframe[src*="kickstarter.com"][src*="video.html"]', 40 | 'object', 41 | 'embed' 42 | ]; 43 | 44 | if (settings.customSelector) { 45 | selectors.push(settings.customSelector); 46 | } 47 | 48 | var ignoreList = '.fitvidsignore'; 49 | 50 | if(settings.ignore) { 51 | ignoreList = ignoreList + ', ' + settings.ignore; 52 | } 53 | 54 | var $allVideos = $(this).find(selectors.join(',')); 55 | $allVideos = $allVideos.not('object object'); // SwfObj conflict patch 56 | $allVideos = $allVideos.not(ignoreList); // Disable FitVids on this video. 57 | 58 | $allVideos.each(function(){ 59 | var $this = $(this); 60 | if($this.parents(ignoreList).length > 0) { 61 | return; // Disable FitVids on this video. 62 | } 63 | if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; } 64 | if ((!$this.css('height') && !$this.css('width')) && (isNaN($this.attr('height')) || isNaN($this.attr('width')))) 65 | { 66 | $this.attr('height', 9); 67 | $this.attr('width', 16); 68 | } 69 | var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(), 70 | width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(), 71 | aspectRatio = height / width; 72 | if(!$this.attr('name')){ 73 | var videoName = 'fitvid' + $.fn.fitVids._count; 74 | $this.attr('name', videoName); 75 | $.fn.fitVids._count++; 76 | } 77 | $this.wrap('
    ').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+'%'); 78 | $this.removeAttr('height').removeAttr('width'); 79 | }); 80 | }); 81 | }; 82 | 83 | // Internal counter for unique video names. 84 | $.fn.fitVids._count = 0; 85 | 86 | // Works with either jQuery or Zepto 87 | })( window.jQuery || window.Zepto ); 88 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-related-links/class-shortcode.php: -------------------------------------------------------------------------------- 1 | run = new GCSS_Related_Links_Run( $plugin->sermons ); 18 | $this->admin = new GCSS_Related_Links_Admin( $this->run ); 19 | 20 | parent::hooks(); 21 | } 22 | 23 | } 24 | 25 | /** 26 | * GC Sermons Related Links Shortcode 27 | * 28 | * @version 0.1.3 29 | * @package GC Sermons 30 | */ 31 | class GCSS_Related_Links_Run extends GCS_Shortcodes_Run_Base { 32 | 33 | /** 34 | * The Shortcode Tag 35 | * @var string 36 | * @since 0.1.0 37 | */ 38 | public $shortcode = 'gc_related_links'; 39 | 40 | /** 41 | * Default attributes applied to the shortcode. 42 | * @var array 43 | * @since 0.1.0 44 | */ 45 | public $atts_defaults = array( 46 | 'sermon_id' => 0, // 'Blank, "recent", or "0" will play the most recent video. 47 | 'recent' => 'recent', // Options: 'recent', 'audio', 'video' 48 | ); 49 | 50 | /** 51 | * Shortcode Output 52 | */ 53 | public function shortcode() { 54 | return gc_get_sermon_related_links( $this->get_sermon() ); 55 | } 56 | 57 | } 58 | 59 | /** 60 | * GC Sermons Related Links Shortcode - Admin 61 | * @version 0.1.3 62 | * @package GC Sermons 63 | */ 64 | class GCSS_Related_Links_Admin extends GCSS_Recent_Admin_Base { 65 | 66 | /** 67 | * Shortcode prefix for field ids. 68 | * 69 | * @var string 70 | * @since 0.1.3 71 | */ 72 | protected $prefix = 're_links_'; 73 | 74 | /** 75 | * Sets up the button 76 | * 77 | * @return array 78 | */ 79 | function js_button_data() { 80 | return array( 81 | 'qt_button_text' => __( 'GC Sermon Links', 'gc-sermons' ), 82 | 'button_tooltip' => __( 'GC Sermon Related Links', 'gc-sermons' ), 83 | 'icon' => 'dashicons-admin-links', 84 | // 'mceView' => true, // The future 85 | ); 86 | } 87 | 88 | /** 89 | * Adds fields to the button modal using CMB2 90 | * 91 | * @param $fields 92 | * @param $button_data 93 | * 94 | * @return array 95 | */ 96 | function fields( $fields, $button_data ) { 97 | 98 | $fields[] = array( 99 | 'name' => __( 'Sermon ID', 'gc-sermons' ), 100 | 'desc' => __( 'Blank, "recent", or "0" will get the most recent sermon\'s speaker info. Otherwise enter a post ID. Click the magnifying glass to search for a Sermon post.', 'gc-sermons' ), 101 | 'id' => $this->prefix . 'sermon_id', 102 | 'type' => 'post_search_text', 103 | 'post_type' => $this->run->sermons->post_type(), 104 | 'select_type' => 'radio', 105 | 'select_behavior' => 'replace', 106 | 'row_classes' => 'check-if-recent', 107 | ); 108 | 109 | $fields[] = array( 110 | 'name' => __( 'Filter Most Recent Sermon By:', 'gc-sermons' ), 111 | 'desc' => __( 'If setting "Sermon ID" above to blank, "recent", or "0", this setting determines which type of most recent sermon to get the related links info for.', 'gc-sermons' ), 112 | 'type' => 'select', 113 | 'id' => $this->prefix . 'recent', 114 | 'default' => $this->atts_defaults['recent'], 115 | 'row_classes' => 'hide-if-not-recent', 116 | 'options' => array( 117 | 'recent' => __( 'Most Recent', 'gc-sermons' ), 118 | 'audio' => __( 'Most Recent with Audio', 'gc-sermons' ), 119 | 'video' => __( 'Most Recent with Video', 'gc-sermons' ), 120 | ), 121 | ); 122 | 123 | return $fields; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-search/class-admin.php: -------------------------------------------------------------------------------- 1 | taxonomies = $taxonomies; 34 | parent::__construct( $run ); 35 | } 36 | 37 | /** 38 | * Sets up the button 39 | * 40 | * @return array 41 | */ 42 | function js_button_data() { 43 | return array( 44 | 'qt_button_text' => __( 'GC Sermons Search', 'gc-sermons' ), 45 | 'button_tooltip' => __( 'GC Sermons Search', 'gc-sermons' ), 46 | 'icon' => 'dashicons-search', 47 | // 'mceView' => true, // The future 48 | ); 49 | } 50 | 51 | /** 52 | * Adds fields to the button modal using CMB2 53 | * 54 | * @param $fields 55 | * @param $button_data 56 | * 57 | * @return array 58 | */ 59 | function fields( $fields, $button_data ) { 60 | 61 | $fields[] = array( 62 | 'name' => __( 'Search:', 'gc-sermons' ), 63 | 'desc' => sprintf( __( 'Select whether form allows searching %s, %s, or both.', 'gc-sermons' ), $this->run->sermons->post_type( 'plural' ), $this->taxonomies->series->taxonomy( 'plural' ) ), 64 | 'id' => $this->prefix . 'search', 65 | 'type' => 'select', 66 | 'default' => $this->atts_defaults['search'], 67 | 'options' => array( 68 | 'sermons' => $this->run->sermons->post_type( 'plural' ), 69 | 'series' => $this->taxonomies->series->taxonomy( 'plural' ), 70 | '' => __( 'Both', 'gc-sermons' ), 71 | ), 72 | ); 73 | 74 | $fields[] = array( 75 | 'name' => __( 'Number of results to show per-page', 'gc-sermons' ), 76 | 'type' => 'text_small', 77 | 'id' => $this->prefix . 'per_page', 78 | 'default' => get_option( 'posts_per_page', $this->atts_defaults['per_page'] ), 79 | ); 80 | 81 | $fields[] = array( 82 | 'name' => __( 'Content', 'gc-sermons' ), 83 | 'type' => 'radio', 84 | 'id' => $this->prefix . 'content', 85 | 'default' => $this->atts_defaults['content'], 86 | 'options' => array( 87 | '' => __( 'None', 'gc-sermons' ), 88 | 'content' => __( 'Sermon Post Content', 'gc-sermons' ), 89 | 'excerpt' => __( 'Sermon Post Excerpt', 'gc-sermons' ), 90 | ), 91 | ); 92 | 93 | $fields[] = array( 94 | 'name' => __( 'Remove Thumbnails', 'gc-sermons' ), 95 | 'type' => 'checkbox', 96 | 'id' => $this->prefix . 'remove_thumbnail', 97 | 'default' => false, 98 | ); 99 | 100 | $fields[] = array( 101 | 'name' => __( 'Thumbnail Size (if included)', 'gc-sermons' ), 102 | 'type' => 'text', 103 | 'id' => $this->prefix . 'thumbnail_size', 104 | 'default' => $this->atts_defaults['thumbnail_size'], 105 | ); 106 | 107 | $fields[] = array( 108 | 'name' => __( 'Max number of columns', 'gc-sermons' ), 109 | 'desc' => __( 'Will vary on device screen width', 'gc-sermons' ), 110 | 'type' => 'radio_inline', 111 | 'options' => array( 1 => 1, 2 => 2, 3 => 3, 4 => 4 ), 112 | 'id' => $this->prefix . 'number_columns', 113 | 'default' => $this->atts_defaults['number_columns'], 114 | ); 115 | 116 | return $fields; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-series/class-run.php: -------------------------------------------------------------------------------- 1 | series = $series; 34 | parent::__construct( $sermons ); 35 | } 36 | 37 | /** 38 | * Default attributes applied to the shortcode. 39 | * @var array 40 | * @since 0.1.0 41 | */ 42 | public $atts_defaults = array( 43 | 'per_page' => 10, // Will use WP's per-page option. 44 | 'remove_dates' => false, 45 | 'remove_thumbnail' => false, 46 | 'thumbnail_size' => 'medium', 47 | 'number_columns' => 2, 48 | 'list_offset' => 0, 49 | 'wrap_classes' => '', 50 | 'remove_pagination' => false, 51 | 52 | // No admin 53 | 'remove_description' => true, 54 | ); 55 | 56 | /** 57 | * Shortcode Output 58 | */ 59 | public function shortcode() { 60 | $allterms = $this->series->get_many( array( 'orderby' => 'sermon_date' ) ); 61 | 62 | if ( empty( $allterms ) ) { 63 | return ''; 64 | } 65 | 66 | $args = $this->get_initial_query_args(); 67 | $total_pages = ceil( count( $allterms ) / $args['posts_per_page'] ); 68 | $allterms = array_splice( $allterms, $args['offset'], $args['posts_per_page'] ); 69 | 70 | if ( empty( $allterms ) ) { 71 | return ''; 72 | } 73 | 74 | $args = $this->get_pagination( $total_pages ); 75 | 76 | $args['terms'] = $this->add_year_index_and_augment_terms( $allterms ); 77 | $args['remove_dates'] = $this->bool_att( 'remove_dates' ); 78 | $args['wrap_classes'] = $this->get_wrap_classes(); 79 | 80 | $content = ''; 81 | $content .= GCS_Style_Loader::get_template( 'list-item-style' ); 82 | $content .= GCS_Template_Loader::get_template( 'series-list', $args ); 83 | 84 | return $content; 85 | } 86 | 87 | public function get_initial_query_args() { 88 | $posts_per_page = (int) $this->att( 'per_page', get_option( 'posts_per_page' ) ); 89 | $paged = (int) get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1; 90 | $offset = ( ( $paged - 1 ) * $posts_per_page ) + $this->att( 'list_offset', 0 ); 91 | 92 | return compact( 'posts_per_page', 'paged', 'offset' ); 93 | } 94 | 95 | public function get_pagination( $total_pages ) { 96 | $nav = array( 'prev_link' => '', 'next_link' => '' ); 97 | 98 | if ( ! $this->bool_att( 'remove_pagination' ) ) { 99 | $nav['prev_link'] = get_previous_posts_link( __( ' Newer', 'gc-sermons' ), $total_pages ); 100 | $nav['next_link'] = get_next_posts_link( __( 'Older ', 'gc-sermons' ), $total_pages ); 101 | } 102 | 103 | return $nav; 104 | } 105 | 106 | public function get_wrap_classes() { 107 | $columns = absint( $this->att( 'number_columns' ) ); 108 | $columns = $columns < 1 ? 1 : $columns; 109 | 110 | return $this->att( 'wrap_classes' ) . ' gc-' . $columns . '-cols gc-series-wrap'; 111 | } 112 | 113 | public function add_year_index_and_augment_terms( $allterms ) { 114 | $terms = array(); 115 | 116 | $do_date = ! $this->bool_att( 'remove_dates' ); 117 | $do_thumb = ! $this->bool_att( 'remove_thumbnail' ); 118 | $do_desc = ! $this->bool_att( 'remove_description' ); 119 | 120 | foreach ( $allterms as $key => $term ) { 121 | $term = $this->get_term_data( $term ); 122 | 123 | $term->do_image = $do_thumb && $term->image; 124 | $term->do_description = $do_desc && $term->description; 125 | $term->url = $term->term_link; 126 | 127 | $terms[ $do_date ? $term->year : 0 ][] = $term; 128 | } 129 | 130 | return $terms; 131 | } 132 | 133 | public function get_term_data( $term ) { 134 | return $this->series->get( $term, array( 'image_size' => $this->att( 'thumbnail_size' ) ) ); 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function( grunt ) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | var pkg = grunt.file.readJSON( 'package.json' ); 6 | 7 | var bannerTemplate = '/**\n' + 8 | ' * <%= pkg.title %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' + 9 | ' * <%= pkg.author.url %>\n' + 10 | ' *\n' + 11 | ' * Copyright (c) <%= grunt.template.today("yyyy") %>;\n' + 12 | ' * Licensed GPLv2+\n' + 13 | ' */\n'; 14 | 15 | var compactBannerTemplate = '/** ' + 16 | '<%= pkg.title %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %> | <%= pkg.author.url %> | Copyright (c) <%= grunt.template.today("yyyy") %>; | Licensed GPLv2+' + 17 | ' **/\n'; 18 | 19 | // Project configuration 20 | grunt.initConfig( { 21 | 22 | pkg: pkg, 23 | 24 | 25 | watch: { 26 | styles: { 27 | files: ['assets/**/*.css','assets/**/*.scss'], 28 | tasks: ['styles'], 29 | options: { 30 | spawn: false, 31 | livereload: true, 32 | debounceDelay: 500 33 | } 34 | }, 35 | scripts: { 36 | files: ['assets/**/*.js'], 37 | tasks: ['scripts'], 38 | options: { 39 | spawn: false, 40 | livereload: true, 41 | debounceDelay: 500 42 | } 43 | }, 44 | php: { 45 | files: ['**/*.php', '!vendor/**.*.php'], 46 | tasks: ['php'], 47 | options: { 48 | spawn: false, 49 | debounceDelay: 500 50 | } 51 | } 52 | }, 53 | 54 | makepot: { 55 | dist: { 56 | options: { 57 | domainPath: '/languages/', 58 | potFilename: pkg.name + '.pot', 59 | type: 'wp-plugin' 60 | } 61 | } 62 | }, 63 | 64 | addtextdomain: { 65 | dist: { 66 | options: { 67 | textdomain: pkg.name 68 | }, 69 | target: { 70 | files: { 71 | src: ['**/*.php'] 72 | } 73 | } 74 | } 75 | }, 76 | 77 | githooks: { 78 | all: { 79 | // create zip and deploy changes to ftp 80 | 'pre-push': 'compress' 81 | } 82 | }, 83 | 84 | replace: { 85 | version_php: { 86 | src: [ 87 | '**/*.php', 88 | '!vendor/**', 89 | ], 90 | overwrite: true, 91 | replacements: [ { 92 | from: /Version:(\s*?)[a-zA-Z0-9\.\-\+]+$/m, 93 | to: 'Version:$1' + pkg.version 94 | }, { 95 | from: /@version(\s*?)[a-zA-Z0-9\.\-\+]+$/m, 96 | to: '@version$1' + pkg.version 97 | }, { 98 | from: /@since(.*?)NEXT/mg, 99 | to: '@since$1' + pkg.version 100 | }, { 101 | from: /VERSION(\s*?)=(\s*?['"])[a-zA-Z0-9\.\-\+]+/mg, 102 | to: 'VERSION$1=$2' + pkg.version 103 | } ] 104 | }, 105 | version_readme: { 106 | src: ['README.md', 'readme.txt'], 107 | overwrite: true, 108 | replacements: [ { 109 | from: /^\*\*Stable tag:\*\*(\s*?)[a-zA-Z0-9.-]+(\s*?)$/mi, 110 | to: '**Stable tag:**$1<%= pkg.version %>$2' 111 | } ] 112 | }, 113 | }, 114 | 115 | compress: { 116 | main: { 117 | options: { 118 | mode: 'zip', 119 | archive: 'gc-sermons.zip' 120 | }, 121 | files: [ { 122 | expand: true, 123 | src: [ 124 | '**', 125 | '!**/**dandelion**.yml', 126 | '!**/**.xml', 127 | '!**/Dockunit.json', 128 | '!**/package.json', 129 | '!**/node_modules/**', 130 | '!**/bin/**', 131 | '!**/tests/**', 132 | '!**/sass/**', 133 | '!**.zip', 134 | '!**/**.orig', 135 | '!**/**.map', 136 | '!**/**Gruntfile.js', 137 | '!**/**composer.json', 138 | '!**/**composer.lock', 139 | '!**/**bower.json', 140 | '!vendor/tgmpa/tgm-plugin-activation/plugins/**', 141 | '!vendor/jtsternberg/shortcode-button/**' 142 | ], 143 | dest: '/gc-sermons' 144 | } ] 145 | } 146 | }, 147 | 148 | githooks: { 149 | all: { 150 | // create zip and deploy changes to ftp 151 | 'pre-push': 'compress' 152 | } 153 | } 154 | 155 | } ); 156 | 157 | // Default task. 158 | grunt.registerTask( 'scripts', [] ); 159 | grunt.registerTask( 'styles', [] ); 160 | grunt.registerTask( 'php', [ 'addtextdomain', 'makepot' ] ); 161 | grunt.registerTask( 'default', ['styles', 'scripts', 'php', 'compress'] ); 162 | 163 | grunt.registerTask( 'version', [ 'styles', 'scripts', 'php', 'replace:version_php', 'replace:version_readme', 'compress' ] ); 164 | 165 | grunt.util.linefeed = '\n'; 166 | }; 167 | -------------------------------------------------------------------------------- /bin/install-wp-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ $# -lt 3 ]; then 4 | echo "usage: $0 [db-host] [wp-version]" 5 | exit 1 6 | fi 7 | 8 | DB_NAME=$1 9 | DB_USER=$2 10 | DB_PASS=$3 11 | DB_HOST=${4-localhost} 12 | WP_VERSION=${5-latest} 13 | 14 | WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} 15 | WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} 16 | 17 | download() { 18 | if [ `which curl` ]; then 19 | curl -s "$1" > "$2"; 20 | elif [ `which wget` ]; then 21 | wget -nv -O "$2" "$1" 22 | fi 23 | } 24 | 25 | if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then 26 | WP_TESTS_TAG="tags/$WP_VERSION" 27 | else 28 | # http serves a single offer, whereas https serves multiple. we only want one 29 | download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json 30 | grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json 31 | LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//') 32 | if [[ -z "$LATEST_VERSION" ]]; then 33 | echo "Latest WordPress version could not be found" 34 | exit 1 35 | fi 36 | WP_TESTS_TAG="tags/$LATEST_VERSION" 37 | fi 38 | 39 | set -ex 40 | 41 | install_wp() { 42 | 43 | if [ -d $WP_CORE_DIR ]; then 44 | return; 45 | fi 46 | 47 | mkdir -p $WP_CORE_DIR 48 | 49 | if [ $WP_VERSION == 'latest' ]; then 50 | local ARCHIVE_NAME='latest' 51 | else 52 | local ARCHIVE_NAME="wordpress-$WP_VERSION" 53 | fi 54 | 55 | download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz 56 | tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR 57 | 58 | download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php 59 | } 60 | 61 | install_test_suite() { 62 | # portable in-place argument for both GNU sed and Mac OSX sed 63 | if [[ $(uname -s) == 'Darwin' ]]; then 64 | local ioption='-i .bak' 65 | else 66 | local ioption='-i' 67 | fi 68 | 69 | # set up testing suite if it doesn't yet exist 70 | if [ ! -d $WP_TESTS_DIR ]; then 71 | # set up testing suite 72 | mkdir -p $WP_TESTS_DIR 73 | svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes 74 | fi 75 | 76 | cd $WP_TESTS_DIR 77 | 78 | if [ ! -f wp-tests-config.php ]; then 79 | download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php 80 | sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" "$WP_TESTS_DIR"/wp-tests-config.php 81 | sed $ioption "s:define( 'WP_DEBUG', true );:define( 'WP_DEBUG', true ); define( 'WP_DEBUG_LOG', true );:" "$WP_TESTS_DIR"/wp-tests-config.php 82 | sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php 83 | sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php 84 | sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php 85 | sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php 86 | fi 87 | 88 | } 89 | 90 | install_required_plugins() { 91 | WDS_SHORTCODES="$WP_CORE_DIR/wp-content/plugins/wds-shortcodes" 92 | CMB2="$WP_CORE_DIR/wp-content/plugins/cmb2" 93 | 94 | if [ ! -d WDS_SHORTCODES ]; then 95 | mkdir -p WDS_SHORTCODES 96 | download https://raw.githubusercontent.com/WebDevStudios/WDS-Shortcodes/master/wds-shortcodes.zip /tmp/wds-shortcodes.zip 97 | unzip /tmp/wds-shortcodes.zip -d WDS_SHORTCODES 98 | fi 99 | 100 | if [ ! -d CMB2 ]; then 101 | mkdir -p CMB2 102 | download https://downloads.wordpress.org/plugin/cmb2.zip /tmp/cmb2.zip 103 | unzip /tmp/cmb2.zip -d CMB2 104 | fi 105 | } 106 | 107 | install_db() { 108 | # parse DB_HOST for port or socket references 109 | local PARTS=(${DB_HOST//\:/ }) 110 | local DB_HOSTNAME=${PARTS[0]}; 111 | local DB_SOCK_OR_PORT=${PARTS[1]}; 112 | local EXTRA="" 113 | 114 | if ! [ -z $DB_HOSTNAME ] ; then 115 | if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then 116 | EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" 117 | elif ! [ -z $DB_SOCK_OR_PORT ] ; then 118 | EXTRA=" --socket=$DB_SOCK_OR_PORT" 119 | elif ! [ -z $DB_HOSTNAME ] ; then 120 | EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" 121 | fi 122 | fi 123 | 124 | # create database 125 | mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA 126 | } 127 | 128 | install_wp 129 | install_test_suite 130 | install_required_plugins 131 | install_db 132 | -------------------------------------------------------------------------------- /includes/class-style-loader.php: -------------------------------------------------------------------------------- 1 | force = $force; 54 | parent::__construct( $css_template, $name, $args ); 55 | } 56 | 57 | /** 58 | * Loads the view and outputs it 59 | * 60 | * @since 0.1.3 61 | * 62 | * @param boolean $echo Whether to output or return the template 63 | * 64 | * @return string Rendered template 65 | */ 66 | public function load( $echo = false ) { 67 | $content = ''; 68 | 69 | // If we haven't done the template before (or we're forcing it)... 70 | if ( ! isset( self::$done[ $this->template ] ) || $this->force ) { 71 | // Then get the content. 72 | $content = parent::load( false ); 73 | } 74 | 75 | // If we got content... 76 | if ( $content ) { 77 | 78 | $content = $this->format_css_tag( $content ); 79 | 80 | // Ok, this one is done, don't load it again. 81 | self::$done[ $this->template ] = $this->template; 82 | } 83 | 84 | if ( ! $echo ) { 85 | return $content; 86 | } 87 | 88 | echo $content; 89 | } 90 | 91 | /** 92 | * Minifies css and wraps in style tag. 93 | * 94 | * @since 0.1.3 95 | * 96 | * @param string $content CSS content to format/wrap. 97 | * 98 | * @return string Formatted CSS in style tag. 99 | */ 100 | protected function format_css_tag( $content ) { 101 | 102 | // Remove comments. 103 | $content = preg_replace( '!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $content ); 104 | 105 | // Remove space after colons. 106 | $content = str_replace( ': ', ':', $content ); 107 | // Remove whitespace. 108 | $content = str_replace( array( "\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $content ); 109 | 110 | // Then wrap in a style tag. 111 | $content = "\n\n"; 112 | 113 | return $content; 114 | } 115 | 116 | /** 117 | * Get a rendered HTML view with the given arguments and return the view's contents. 118 | * 119 | * @since 0.1.3 120 | * 121 | * @param string $template The template file name, relative to the includes/templates/ folder 122 | * - without .php extension 123 | * @param string $name The name of the specialised template. If array, will take the place of the $args. 124 | * @param array $args An array of arguments to extract as variables into the template 125 | * 126 | * @return string Rendered template output 127 | */ 128 | public static function get_template( $template, $name = null, array $args = array() ) { 129 | $view = new self( $template, $name, $args ); 130 | return $view->load(); 131 | } 132 | 133 | /** 134 | * Render an HTML view with the given arguments and output the view's contents. 135 | * 136 | * @since 0.1.3 137 | * 138 | * @param string $template The template file name, relative to the includes/templates/ folder 139 | * - without .php extension 140 | * @param string $name The name of the specialised template. If array, will take the place of the $args. 141 | * @param array $args An array of arguments to extract as variables into the template 142 | * 143 | * @return void 144 | */ 145 | public static function output_template( $template, $name = null, array $args = array() ) { 146 | $view = new self( $template, $name, $args ); 147 | $view->load( 1 ); 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-play-button/class-run.php: -------------------------------------------------------------------------------- 1 | 0, 27 | 'icon_color' => '#000000', 28 | 'icon_size' => 'large', 29 | 'icon_class' => 'fa-youtube-play', 30 | 31 | // no admin 32 | 'do_scripts' => true, 33 | ); 34 | 35 | /** 36 | * Shortcode Output 37 | */ 38 | public function shortcode() { 39 | 40 | $sermon = $this->get_sermon(); 41 | 42 | if ( ! $sermon || ! isset( $sermon->ID ) ) { 43 | return apply_filters( 'gcs_sermon_play_button_shortcode_output', GCS_Template_Loader::get_template( 'play-button-shortcode-not-found' ), $this ); 44 | } 45 | 46 | if ( $this->att( 'do_scripts' ) ) { 47 | $this->do_scripts(); 48 | } 49 | 50 | $output = GCS_Style_Loader::get_template( 'play-button-shortcode-style' ); 51 | 52 | list( $style, $has_icon_font_size ) = $this->get_inline_styles(); 53 | 54 | $output .= apply_filters( 'gcs_sermon_play_button_shortcode_output', GCS_Template_Loader::get_template( 55 | 'play-button-shortcode', 56 | array( 57 | // Get our extra_class attribute 58 | 'extra_classes' => $this->get_extra_classes( $has_icon_font_size ), 59 | 'sermond_id' => $sermon->ID, 60 | 'style' => $style, 61 | 'video_url' => get_post_meta( $sermon->ID, 'gc_sermon_video_url', 1 ), 62 | ) 63 | ), $this ); 64 | 65 | return $output; 66 | } 67 | 68 | protected function most_recent_sermon() { 69 | return $this->sermons->most_recent_with_video(); 70 | } 71 | 72 | public function get_inline_styles() { 73 | $style = ''; 74 | $has_icon_font_size = false; 75 | 76 | if ( $this->att( 'icon_color' ) || $this->att( 'icon_size' ) ) { 77 | $style = ' style="'; 78 | // Get/check our text_color attribute 79 | if ( $this->att( 'icon_color' ) ) { 80 | $text_color = sanitize_text_field( $this->att( 'icon_color' ) ); 81 | $style .= 'color: ' . $text_color .';'; 82 | } 83 | if ( is_numeric( $this->att( 'icon_size' ) ) ) { 84 | $has_icon_font_size = absint( $this->att( 'icon_size' ) ); 85 | $style .= 'font-size: ' . $has_icon_font_size .'em;'; 86 | } 87 | $style .= '"'; 88 | } 89 | 90 | return array( $style, $has_icon_font_size ); 91 | } 92 | 93 | public function get_extra_classes( $has_icon_font_size = false ) { 94 | $classes = ' ' . implode( ' ', array_map( 'esc_attr', explode( ' ', $this->att( 'icon_class' ) ) ) ); 95 | 96 | if ( ! $has_icon_font_size ) { 97 | $classes .= ' icon-size-' . esc_attr( $this->att( 'icon_size', 'large' ) ); 98 | } 99 | 100 | return $classes; 101 | } 102 | 103 | public function do_scripts() { 104 | 105 | // Enqueue whatever version of fontawesome that's registereed (if it is registered) 106 | wp_enqueue_style( 'qode_font_awesome-css' ); 107 | wp_enqueue_style( 'font_awesome' ); 108 | wp_enqueue_style( 'font-awesome' ); 109 | wp_enqueue_style( 'fontawesome' ); 110 | 111 | add_action( 'wp_footer', array( $this, 'video_modal' ) ); 112 | 113 | wp_enqueue_script( 114 | 'fitvids', 115 | GC_Sermons_Plugin::$url . 'assets/js/vendor/jquery.fitvids.js', 116 | array( 'jquery' ), 117 | '1.1', 118 | true 119 | ); 120 | 121 | wp_enqueue_script( 122 | 'gc-sermon-videos', 123 | GC_Sermons_Plugin::$url . 'assets/js/gc-sermon-videos.js', 124 | array( 'fitvids' ), 125 | GC_Sermons_Plugin::VERSION, 126 | true 127 | ); 128 | } 129 | 130 | public function video_modal() { 131 | static $done; 132 | 133 | // Get shortcode instances 134 | $shortcodes = WDS_Shortcode_Instances::get( $this->shortcode ); 135 | 136 | if ( $done || empty( $shortcodes ) ) { 137 | return; 138 | } 139 | 140 | $videos = array(); 141 | foreach ( $shortcodes as $shortcode ) { 142 | // Check for found sermons 143 | if ( ! ( $sermon = $shortcode->att( 'sermon' ) ) ) { 144 | continue; 145 | } 146 | 147 | // Check for video player 148 | if ( ! ( $player = $sermon->get_video_player() ) ) { 149 | return; 150 | } 151 | 152 | // Ok, add the video player 153 | $videos[ $sermon->ID ] = $player; 154 | } 155 | 156 | if ( ! empty( $videos ) ) { 157 | echo new GCS_Template_Loader( 'play-button-shortcode-modal-videos', array( 158 | 'videos' => $videos, 159 | ) ); 160 | } 161 | 162 | $done = true; 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-search/class-series-search-run.php: -------------------------------------------------------------------------------- 1 | search_query = $search_query; 42 | $this->current_page = absint( gc__get_arg( 'results-page', 1 ) ); 43 | 44 | parent::__construct( $sermons, $series ); 45 | 46 | $this->create_shortcode_object( 47 | shortcode_atts( $this->atts_defaults, $atts, $this->shortcode ), 48 | '' 49 | ); 50 | } 51 | 52 | public function get_search_results() { 53 | $args = $this->get_initial_query_args(); 54 | 55 | $number = $args['number']; 56 | $offset = $args['offset']; 57 | 58 | // We want to get them all. (well, up to 1000). 59 | $args['number'] = 1000; 60 | $args['offset'] = 0; 61 | $args['hide_empty'] = true; 62 | $allterms = $this->series->search( sanitize_text_field( $this->search_query ), $args ); 63 | $allterms = $this->orderby_post_date( $allterms ); 64 | 65 | if ( empty( $allterms ) ) { 66 | return ''; 67 | } 68 | 69 | $count = count( $allterms ); 70 | $total_pages = ceil( $count / $number ); 71 | $allterms = array_splice( $allterms, $offset, $number ); 72 | 73 | if ( $count > 900 ) { 74 | // Whoops, warn! 75 | trigger_error( 'You have more than 900 sermon series terms, and search queries which are requesting greater than 900 sermon series terms. You may want to look into additional performance optimizations.', E_USER_WARNING ); 76 | } 77 | 78 | $args = $this->get_pagination( $total_pages ); 79 | 80 | $args['terms'] = array( $this->augment_terms( $allterms ) ); 81 | $args['remove_dates'] = true; 82 | $args['wrap_classes'] = $this->get_wrap_classes(); 83 | 84 | $this->results = ''; 85 | $this->results .= GCS_Style_Loader::get_template( 'list-item-style' ); 86 | $this->results .= GCS_Template_Loader::get_template( 'series-list', $args ); 87 | 88 | return $this->results; 89 | } 90 | 91 | public function get_initial_query_args() { 92 | $number = (int) $this->att( 'per_page', get_option( 'number' ) ); 93 | $offset = ( ( $this->current_page - 1 ) * $number ) + $this->att( 'list_offset', 0 ); 94 | 95 | return compact( 'number', 'offset' ); 96 | } 97 | 98 | public function get_pagination( $total_pages ) { 99 | $nav = array( 'prev_link' => '', 'next_link' => '' ); 100 | 101 | if ( ! $this->bool_att( 'remove_pagination' ) ) { 102 | $nav['prev_link'] = gc_search_get_previous_results_link(); 103 | $nav['next_link'] = gc_search_get_next_results_link( $total_pages ); 104 | } 105 | 106 | return $nav; 107 | } 108 | 109 | public function get_wrap_classes() { 110 | return parent::get_wrap_classes() . ' gc-series-search-wrap'; 111 | } 112 | 113 | public function augment_terms( $allterms ) { 114 | $do_thumb = ! $this->bool_att( 'remove_thumbnail' ); 115 | $do_desc = ! $this->bool_att( 'remove_description' ); 116 | 117 | foreach ( $allterms as $key => $term ) { 118 | $term = $this->get_term_data( $term ); 119 | 120 | $term->do_image = $do_thumb && $term->image; 121 | $term->do_description = $do_desc && $term->description; 122 | $term->url = $term->term_link; 123 | 124 | $allterms[ $key ] = $term; 125 | } 126 | 127 | return $allterms; 128 | } 129 | 130 | public function orderby_post_date( $allterms ) { 131 | $ordered = array(); 132 | if ( empty( $allterms ) ) { 133 | return $ordered; 134 | } 135 | foreach ( $allterms as $key => $term ) { 136 | $query = new WP_Query( array( 137 | 'post_status' => 'publish', 138 | 'posts_per_page' => 1, 139 | 'no_found_rows' => true, 140 | 'cache_results' => false, 141 | 'suppress_filters' => true, 142 | 'tax_query' => array( 143 | array( 144 | 'taxonomy' => $this->series->taxonomy(), 145 | 'field' => 'slug', 146 | 'terms' => $term->slug, 147 | ), 148 | ), 149 | ) ); 150 | 151 | if ( $query->have_posts() ) { 152 | $ordered[ strtotime( $query->post->post_date ) ] = $term; 153 | } 154 | 155 | } 156 | 157 | krsort( $ordered ); 158 | 159 | return $ordered; 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /templates/list-item-style.css: -------------------------------------------------------------------------------- 1 | .gc-series-wrap h4 { 2 | clear: both; 3 | border-bottom: 1px solid rgba(0,0,0,.5); 4 | padding: .5em; 5 | } 6 | 7 | .gc-sermons-list { 8 | clear: both; 9 | margin-left: 0; 10 | margin-right: 0; 11 | padding-left: 0; 12 | padding-right: 0; 13 | } 14 | 15 | .gc-sermons-list:after { 16 | content: ''; 17 | display: block; 18 | clear: both; 19 | } 20 | 21 | .gc-sermons-list:after { 22 | content: ''; 23 | display: block; 24 | clear: both; 25 | } 26 | 27 | .gc-item { 28 | position: relative; 29 | display: block; 30 | list-style-type: none; 31 | float: left; 32 | padding: .5em; 33 | } 34 | 35 | .gc-1-cols .gc-item { 36 | float: none; 37 | } 38 | 39 | .gc-2-cols .gc-item { 40 | width: 50%; 41 | } 42 | 43 | .gc-3-cols .gc-item { 44 | width: 33.333333%; 45 | } 46 | 47 | .gc-4-cols .gc-item { 48 | width: 25%; 49 | } 50 | 51 | .gc-4-cols .gc-item h3 { 52 | font-size: 1.5em; 53 | } 54 | 55 | .gc-item, .gc-item * { 56 | -moz-box-sizing: border-box; 57 | -webkit-box-sizing: border-box; 58 | box-sizing: border-box; 59 | } 60 | 61 | .gc-2-cols .gc-item:nth-child(2n+1), 62 | .gc-3-cols .gc-item:nth-child(3n+1), 63 | .gc-4-cols .gc-item:nth-child(4n+1) { 64 | clear: both; 65 | } 66 | 67 | .gc-item img { 68 | max-width: 100%; 69 | height: auto; 70 | } 71 | 72 | .gc-item-link { 73 | display: inline-block; 74 | position: relative; 75 | margin: 0; 76 | width: 100%; 77 | /*overflow: hidden;*/ 78 | } 79 | 80 | .gc-no-thumb .gc-item-link { 81 | background-color: rgba(0,0,0,.5); 82 | padding: .9em .5em .95em; 83 | -webkit-transition: background-color .3s ease-in-out; 84 | -moz-transition: background-color .3s ease-in-out; 85 | -o-transition: background-color .3s ease-in-out; 86 | -ms-transition: background-color .3s ease-in-out; 87 | } 88 | 89 | .gc-no-thumb .gc-item-link:hover { 90 | background-color: rgba(0,0,0,.7); 91 | } 92 | 93 | .gc-thumb .gc-item-link:hover .gc-sermons-shader, 94 | .gc-thumb .gc-item-link:hover .gc-sermons-table-wrapper { 95 | opacity: 0; 96 | } 97 | 98 | .gc-sermons-table-wrapper { 99 | overflow: hidden; 100 | } 101 | 102 | .gc-sermons-shader, 103 | .gc-sermons-table-wrapper, 104 | .gc-item-link table { 105 | position: relative; 106 | } 107 | 108 | .gc-thumb .gc-sermons-shader, 109 | .gc-thumb .gc-sermons-table-wrapper, 110 | .gc-thumb table { 111 | position: absolute; 112 | -webkit-transition: opacity .3s ease-in-out; 113 | -moz-transition: opacity .3s ease-in-out; 114 | -o-transition: opacity .3s ease-in-out; 115 | -ms-transition: opacity .3s ease-in-out; 116 | } 117 | 118 | .gc-thumb .gc-sermons-shader, 119 | .gc-thumb .gc-sermons-table-wrapper, 120 | .gc-item-link table { 121 | width: 100%; 122 | height: 100%; 123 | left: 0; 124 | top: 0; 125 | } 126 | 127 | .gc-item-link table { 128 | border: 10px solid transparent; 129 | } 130 | 131 | .gc-item-link img { 132 | display: block; 133 | position: relative; 134 | width: 100%; 135 | } 136 | 137 | .gc-item-link .gc-sermons-shader { 138 | background-color: rgba(0,0,0,.5); 139 | } 140 | 141 | .gc-item-link td { 142 | padding: 0; 143 | vertical-align: middle; 144 | background: none; 145 | } 146 | 147 | .gc-item h3 { 148 | color: #fff; 149 | font-size: 2em; 150 | position: relative; 151 | padding-bottom: 1.5em; 152 | } 153 | 154 | .gc-item h3:after { 155 | position: absolute; 156 | content: '→'; 157 | font-family: monospace; 158 | font-size: 2em; 159 | display: block; 160 | line-height: .25em; 161 | text-align: center; 162 | bottom: .5em; 163 | height: 0; 164 | width: 100%; 165 | left: 50%; 166 | margin-left: -50%; 167 | padding: 0; 168 | -webkit-transition: all .1s ease-in-out; 169 | -moz-transition: all .1s ease-in-out; 170 | -o-transition: all .1s ease-in-out; 171 | -ms-transition: all .1s ease-in-out; 172 | } 173 | 174 | .gc-no-thumb .gc-link:hover h3:after { 175 | font-size: 2.5em; 176 | bottom: .46em; 177 | } 178 | 179 | .gc-next-link { 180 | float: right; 181 | } 182 | 183 | .gc-next-link a span, .gc-prev-link a:before { 184 | display: inline-block; 185 | font-family: monospace; 186 | font-size: 2em; 187 | } 188 | 189 | .gc-prev-link a span { 190 | display: none; 191 | } 192 | 193 | .gc-prev-link a:before { 194 | /* Because → looks better w/ monospace font, so flip it. */ 195 | content: '→'; 196 | -webkit-transform:rotateY(180deg); 197 | -moz-transform:rotateY(180deg); 198 | -o-transform:rotateY(180deg); 199 | -ms-transform:rotateY(180deg); 200 | } 201 | 202 | .gc-prev-next:after { 203 | content: ''; 204 | display: block; 205 | clear: both; 206 | } 207 | 208 | @media only screen and (max-width : 1000px) { 209 | 210 | .gc-item h3 { 211 | font-size: 1.5em; 212 | } 213 | 214 | .gc-4-cols .gc-item h3 { 215 | font-size: 1em; 216 | } 217 | 218 | } 219 | 220 | @media only screen and (max-width : 775px) { 221 | 222 | .gc-3-cols .gc-item, 223 | .gc-4-cols .gc-item { 224 | width: 50%; 225 | } 226 | 227 | .gc-3-cols .gc-item:nth-child(3n+1), 228 | .gc-4-cols .gc-item:nth-child(4n+1) { 229 | clear: none; 230 | } 231 | 232 | .gc-3-cols .gc-item:nth-child(2n+1), 233 | .gc-4-cols .gc-item:nth-child(2n+1) { 234 | clear: both; 235 | } 236 | 237 | .gc-4-cols .gc-item h3 { 238 | font-size: 1.5em; 239 | } 240 | 241 | } 242 | 243 | @media only screen and (max-width : 600px) { 244 | 245 | .gc-2-cols .gc-item, 246 | .gc-3-cols .gc-item, 247 | .gc-4-cols .gc-item { 248 | width: 100%; 249 | } 250 | 251 | .gc-item h3 { 252 | font-size: 1.4em; 253 | } 254 | 255 | } 256 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-search/class-run.php: -------------------------------------------------------------------------------- 1 | '', 25 | 'per_page' => 10, // Will use WP's per-page option. 26 | 'content' => 'excerpt', 27 | 'remove_thumbnail' => false, 28 | 'thumbnail_size' => 'medium', 29 | 'number_columns' => 2, 30 | 31 | // No admin UI. 32 | 33 | // Sermon specific 34 | 'list_offset' => 0, 35 | 'wrap_classes' => '', 36 | 'remove_pagination' => false, 37 | 'related_speaker' => 0, 38 | 'related_series' => 0, 39 | 40 | // Series specific 41 | 'remove_description' => true, 42 | 43 | 'sermon_search_args' => array(), 44 | 'series_search_args' => array(), 45 | ); 46 | 47 | /** 48 | * GCS_Sermons object 49 | * 50 | * @var GCS_Sermons 51 | * @since 0.1.0 52 | */ 53 | public $taxonomies; 54 | 55 | /** 56 | * The current search query. 57 | * 58 | * @var string 59 | */ 60 | protected $search_query = ''; 61 | 62 | /** 63 | * Constructor 64 | * 65 | * @since 0.1.3 66 | * 67 | * @param GCS_Sermons $sermons 68 | * @param GCS_Taxonomies $taxonomies 69 | */ 70 | public function __construct( GCS_Sermons $sermons, GCS_Taxonomies $taxonomies ) { 71 | 72 | $this->taxonomies = $taxonomies; 73 | parent::__construct( $sermons ); 74 | } 75 | 76 | /** 77 | * Shortcode Output 78 | */ 79 | public function shortcode() { 80 | $this->search_query = gc__get_arg( 'sermon-search', '' ); 81 | $show_results = gc__get_arg( 'results-for', '' ); 82 | 83 | $series_slug = $this->taxonomies->series->taxonomy(); 84 | $cpt_slug = $this->sermons->post_type(); 85 | 86 | $to_search = $this->att( 'search' ); 87 | $search_both = ! $to_search; 88 | 89 | $format = current_theme_supports( 'html5', 'search-form' ) ? 'html5' : 'xhtml'; 90 | $format = apply_filters( 'search_form_format', $format ); 91 | $template = 'searchform' . ( 'xhtml' === $format ? '-' . $format : '' ); 92 | 93 | $args = array( 94 | 'search_query' => $this->search_query, 95 | 'action_url' => add_query_arg( 'sermon-search', 1 ), 96 | 'sermons_value' => $cpt_slug, 97 | 'sermons_label' => $this->sermons->post_type( 'singular' ), 98 | 'series_value' => $series_slug, 99 | 'series_label' => $this->taxonomies->series->taxonomy( 'singular' ), 100 | 'show_filter' => $search_both, 101 | 'show_results' => $show_results, 102 | ); 103 | 104 | $content = GCS_Template_Loader::get_template( $template, $args ); 105 | 106 | // If a search was performed, let's get the results. 107 | if ( $this->search_query ) { 108 | 109 | if ( strlen( $this->search_query ) < 3 ) { 110 | // Uh-oh, we need at least 3 characters. 111 | $content .= GCS_Template_Loader::get_template( 'search-query-error' ); 112 | } else { 113 | 114 | $show_sermon_results = ! $show_results || $cpt_slug === $show_results; 115 | $show_series_results = ! $show_results || $series_slug === $show_results; 116 | 117 | $search_sermons = $search_both || in_array( $to_search, array( 'sermons' ), 1 ); 118 | $search_series = $search_both || in_array( $to_search, array( 'series' ), 1 ); 119 | 120 | if ( $search_sermons && $show_sermon_results ) { 121 | $content .= $this->sermon_search_results(); 122 | } 123 | 124 | if ( $search_series && $show_series_results ) { 125 | $content .= $this->series_search_results(); 126 | } 127 | 128 | } 129 | } 130 | 131 | return $content; 132 | } 133 | 134 | protected function sermon_search_results() { 135 | $atts = $this->atts; 136 | unset( $atts['search'] ); 137 | unset( $atts['wrap_classes'] ); 138 | 139 | $atts = wp_parse_args( $atts, $this->att( 'sermon_search_args', array() ) ); 140 | 141 | $search = new GCSS_Sermons_Search_Run( $this->search_query, $this->sermons, $this->taxonomies ); 142 | $search->get_search_results( $atts ); 143 | 144 | return GCS_Template_Loader::get_template( 'sermon-search-results', array( 145 | 'wrap_classes' => $this->att( 'wrap_classes' ), 146 | 'results' => empty( $search->results ) ? __( 'No results.', 'gc-sermons' ) : $search->results, 147 | 'search_notice' => sprintf( 148 | __( '%s search results for: %s', 'gc-sermons' ), 149 | $this->sermons->post_type( 'singular' ), 150 | esc_html( $this->search_query ) 151 | ), 152 | ) ); 153 | 154 | return $search; 155 | } 156 | 157 | protected function series_search_results() { 158 | $atts = $this->atts; 159 | unset( $atts['search'] ); 160 | unset( $atts['wrap_classes'] ); 161 | 162 | $atts = wp_parse_args( $atts, $this->att( 'series_search_args', array() ) ); 163 | 164 | $search = new GCSS_Series_Search_Run( $this->search_query, $atts, $this->sermons, $this->taxonomies->series ); 165 | $search->get_search_results(); 166 | 167 | return GCS_Template_Loader::get_template( 'series-search-results', array( 168 | 'wrap_classes' => $this->att( 'wrap_classes' ), 169 | 'results' => empty( $search->results ) ? __( 'No results.', 'gc-sermons' ) : $search->results, 170 | 'search_notice' => sprintf( 171 | __( '%s search results for: %s', 'gc-sermons' ), 172 | $this->taxonomies->series->taxonomy( 'singular' ), 173 | esc_html( $this->search_query ) 174 | ), 175 | ) ); 176 | } 177 | 178 | } 179 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | ## [Unreleased][unreleased] 5 | 6 | ## 0.2.1 - 2018-08-31 7 | 8 | - Fix the `label_coming_soon` method and only check for posts in our post-type 9 | - Use `$this->post_type()`, not (wrong) hard-coded post-type string 10 | - Fix `get_the_id` 11 | 12 | ## 0.2.0 - 2018-08-28 13 | 14 | ### Enhancements 15 | 16 | - Helper functions for getting the GC Sermons augmented taxonomy term objects. 17 | - New helper functions: 18 | - `gc_get_series_object( $term = 0, $args = array() )` 19 | - `gc_get_speaker_object( $term = 0, $args = array() )` 20 | - `gc_get_topic_object( $term = 0, $args = array() )` 21 | - `gc_get_tag_object( $term = 0, $args = array() )` 22 | - `gc_get_scripture_object( $term = 0, $args = array() )` 23 | 24 | ### Bug Fixes 25 | 26 | - Make sure `GCS_Taxonomies_Base::filter_values` runs (so that custom post-type and taxonomy overrides work). 27 | - fix composer.json license value to be compatible with packagist 28 | 29 | ## 0.1.6 - 2016-06-08 30 | 31 | ### Enhancements 32 | 33 | * Move loading of plugin's classes to the `'plugins_loaded'` hook for more flexibility. 34 | * Output "No results" string when Sermon/Series search results are empty. 35 | * Update shortcode-button dependency to fix modal displaying before CSS loads. 36 | 37 | ### Bug Fixes 38 | 39 | * Fix required plugins notices. WDS Shortcodes is now bundled and not required for installation. 40 | * Fix php notice caused by looping an empty array. 41 | 42 | ## 0.1.5 - 2016-06-01 43 | 44 | ### Enhancements 45 | 46 | * Add sermon/series search shortcode. 47 | * Add `GCS_Taxonomies_Base::search()` method for searching for terms in the taxonomies. 48 | * Move some functionality in series shortcode to dedicated methods. 49 | * Add wrapper for `get_terms` to account for changes in WP 4.5 where taxonomy is expected as part of the arguments.. 50 | * Update WDS-Shortcodes dependency. 51 | 52 | ### Bug Fixes 53 | 54 | * Fix bug where the no-thumb class may not be added properly when thumbs are disabled in shortcodes. 55 | * Tidy up debug/whitespace stuff. 56 | * Fix bug where last page may not show because of rounding error. 57 | * Update sermons shortcode to account for inception issues. 58 | * Cleanup shortcodes class, fixing bad property names. 59 | 60 | ### Other 61 | 62 | * Move taxonomy-based files to taxonomy includes directory, and post-type-based files to post-type includes directory. 63 | * Pass the series taxonomy object to `GCSS_Series_Run` (dependency injection). 64 | 65 | ## 0.1.4 - 2016-05-30 66 | 67 | ### Enhancements 68 | 69 | - Shortcodes, shortcodes, shortcodes. Also, this changelog. 70 | - Update readme, pointing to the wiki. 71 | - Filter, `gc_do_sermon_series_fallback_image`, to disable image fallback. 72 | - Update the term-image column and add a term-edit link. 73 | - Move shortcode files around, and add video/audio player shortcodes. 74 | - Clean up "recent" shortcodes and nicer UX. 75 | - Update dependencies to fix some JS issues. 76 | - Add speaker/series filters to the sermon shortcode. 77 | - Add a prefix to shortcode fields, and method to de-prefix before inserting shortcode. 78 | - Add a filter on the template content output. 79 | - Update sermons shortcode, and make things more generic to be shared. 80 | - Revamp/cleanup shortcodes and finalize the series shortcodes. 81 | - Update wds-shortcodes dependency to get the bool_att method, for getting boolean values from shortcode values. 82 | - Add `GCS_Template_Loader::maybe_output` for doing condtional output in templates. 83 | - Update Template Loader. 84 | - Clean up some typos. 85 | - Add image column to speakers/series taxonomies. 86 | - Add several shortcodes, series image fallback for sermson, allow future posts, etc. 87 | - Rename file to match file/class nameing convention. 88 | - Enable future posts to be displayed (with "coming soon") text on the front-end. 89 | - Make audio player wrap class consistent. 90 | - Make `GCS_Shortcodes_Play_Button` properties accessible. 91 | - Implement template loader to allow overriding in themes, etc. 92 | 93 | ## 0.1.3 - 2016-06-01 94 | 95 | - Add "Scripture" Taxonomy. 96 | - Fix `"gcs_cmb2_box_args_{$this->id}_{$cmb_id}"` filter. 97 | 98 | ## 0.1.2 - 2016-04-14 99 | 100 | - Move css to separate css templates. 101 | - `most_recent_with_audio` method should search for audio, not video. 102 | 103 | ## 0.1.1 - 2016-04-14 104 | 105 | - Specify rewite slugs for all taxonomies. 106 | - When calling `get_audio_player`, init media. 107 | - Be more discerning when removing metaboxes, and replace the featured image metabox. 108 | - Use `plugins_loaded` hook to filter the post-type/taxonomy values so that the filter happens early (before init). 109 | - Update to series column. Replace with image, if one is set. 110 | - Check if `gc_staff` is loaded, and change speaker connected field and augmented data. 111 | - Fix textdomains. 112 | - Add sermon `get` and `get_many` methods. 113 | - build a series image when we only have a url. 114 | - Only get the user avatar if there is no speaker image set. 115 | - on post save, asynchronously save the sermon series terms in order of recent sermons. 116 | - Allow a `series_image_fallback`. 117 | - New `GCS_Sermon_Post` methods, `permalink`, `title`, `series_image`, `get_others_in_series`, `get_others_by_speaker`. 118 | - Make play button shortcode enqueue scripts/styles and for the video modal to actually work. 119 | - Add `get_video_player` method to sermon post class. 120 | - make `url`, `path`, `dir` publicly accessible variables. 121 | - Add `wds-shortcodes` as dependency. 122 | - Add `GCS_Sermon_Post` method for getting the sermon post meta. 123 | - Add `GCS_Sermon_Post` method for getting the sermon audio player. 124 | - Add methods to `GCS_Sermon_Post` for getting the post's series or speaker's term object. 125 | - Add addional CMB2 field types and add related links, etc to sermon CPT. 126 | - Add several utility methods for getting taxonomy term objects, and augmenting with additional info. 127 | - Update rewrite for sermons. 128 | - Fix a bug with taxonomy `most_recent`. 129 | - Differentiate between taxonomy/post-type slug, and the object identifier (since slug can be changed via filter). 130 | - clean up composer.json. -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-sermons/class-admin.php: -------------------------------------------------------------------------------- 1 | taxonomies = $taxonomies; 35 | parent::__construct( $run ); 36 | 37 | add_filter( "{$this->shortcode}_shortcode_fields", array( $this, 'return_taxonomy_term_id_only' ), 10 ); 38 | } 39 | 40 | /** 41 | * Sets up the button 42 | * 43 | * @return array 44 | */ 45 | function js_button_data() { 46 | return array( 47 | 'qt_button_text' => __( 'GC Sermons', 'gc-sermons' ), 48 | 'button_tooltip' => __( 'GC Sermons', 'gc-sermons' ), 49 | 'icon' => $this->run->sermons->arg_overrides['menu_icon'], 50 | // 'mceView' => true, // The future 51 | ); 52 | } 53 | 54 | /** 55 | * Adds fields to the button modal using CMB2 56 | * 57 | * @param $fields 58 | * @param $button_data 59 | * 60 | * @return array 61 | */ 62 | function fields( $fields, $button_data ) { 63 | 64 | $fields[] = array( 65 | 'name' => __( 'Number of sermons to show per-page', 'gc-sermons' ), 66 | 'type' => 'text_small', 67 | 'id' => $this->prefix . 'per_page', 68 | 'default' => get_option( 'posts_per_page', $this->atts_defaults['per_page'] ), 69 | ); 70 | 71 | $fields[] = array( 72 | 'name' => sprintf( _x( 'Optionally select to limit %1$s by %2$s', 'limit sermons by sermon series.', 'gc-sermons' ), $this->run->sermons->post_type( 'plural' ), $this->taxonomies->series->taxonomy( 'plural' ) ), 73 | 'desc' => sprintf( __( 'Start typing to search. Enter "this" to use this post\'s %s.', 'gc-sermons' ), $this->taxonomies->series->taxonomy( 'singular' ) ), 74 | 'type' => 'term_select', 75 | 'apply_term' => false, 76 | 'id' => $this->prefix . 'related_series', 77 | 'taxonomy' => $this->taxonomies->series->taxonomy(), 78 | 'attributes' => array( 79 | 'data-min-length' => 2, 80 | 'data-delay' => 100, 81 | ), 82 | ); 83 | 84 | $fields[] = array( 85 | 'name' => sprintf( _x( 'Optionally select to limit %1$s by %2$s', 'limit sermons by sermon speaker.', 'gc-sermons' ), $this->run->sermons->post_type( 'plural' ), $this->taxonomies->speaker->taxonomy( 'plural' ) ), 86 | 'desc' => sprintf( __( 'Start typing to search. Enter "this" to use this post\'s %s.', 'gc-sermons' ), $this->taxonomies->speaker->taxonomy( 'singular' ) ), 87 | 'type' => 'term_select', 88 | 'apply_term' => false, 89 | 'id' => $this->prefix . 'related_speaker', 90 | 'taxonomy' => $this->taxonomies->speaker->taxonomy(), 91 | 'attributes' => array( 92 | 'data-min-length' => 2, 93 | 'data-delay' => 100, 94 | ), 95 | ); 96 | 97 | $fields[] = array( 98 | 'name' => __( 'Remove Pagination', 'gc-sermons' ), 99 | 'type' => 'checkbox', 100 | 'id' => $this->prefix . 'remove_pagination', 101 | 'default' => false, 102 | ); 103 | 104 | $fields[] = array( 105 | 'name' => __( 'Content', 'gc-sermons' ), 106 | 'type' => 'radio', 107 | 'id' => $this->prefix . 'content', 108 | 'default' => $this->atts_defaults['content'], 109 | 'options' => array( 110 | '' => __( 'None', 'gc-sermons' ), 111 | 'content' => __( 'Sermon Post Content', 'gc-sermons' ), 112 | 'excerpt' => __( 'Sermon Post Excerpt', 'gc-sermons' ), 113 | ), 114 | ); 115 | 116 | $fields[] = array( 117 | 'name' => __( 'Remove Thumbnails', 'gc-sermons' ), 118 | 'type' => 'checkbox', 119 | 'id' => $this->prefix . 'remove_thumbnail', 120 | 'default' => false, 121 | ); 122 | 123 | $fields[] = array( 124 | 'name' => __( 'Thumbnail Size (if included)', 'gc-sermons' ), 125 | 'type' => 'text', 126 | 'id' => $this->prefix . 'thumbnail_size', 127 | 'default' => $this->atts_defaults['thumbnail_size'], 128 | ); 129 | 130 | $fields[] = array( 131 | 'name' => __( 'Max number of columns', 'gc-sermons' ), 132 | 'desc' => __( 'Will vary on device screen width', 'gc-sermons' ), 133 | 'type' => 'radio_inline', 134 | 'options' => array( 1 => 1, 2 => 2, 3 => 3, 4 => 4 ), 135 | 'id' => $this->prefix . 'number_columns', 136 | 'default' => $this->atts_defaults['number_columns'], 137 | ); 138 | 139 | $fields[] = array( 140 | 'name' => __( 'Offset', 'gc-sermons' ), 141 | 'desc' => __( 'Changes which sermon starts the list', 'gc-sermons' ), 142 | 'type' => 'text_small', 143 | 'id' => $this->prefix . 'list_offset', 144 | 'sanitization_cb' => 'absint', 145 | 'default' => $this->atts_defaults['list_offset'], 146 | ); 147 | 148 | $fields[] = array( 149 | 'name' => __( 'Extra Wrap CSS Classes', 'gc-sermons' ), 150 | 'desc' => __( 'Enter classes separated by spaces (e.g. "class1 class2")', 'gc-sermons' ), 151 | 'type' => 'text', 152 | 'id' => $this->prefix . 'wrap_classes', 153 | 'default' => $this->atts_defaults['wrap_classes'], 154 | ); 155 | 156 | return $fields; 157 | } 158 | 159 | public function return_taxonomy_term_id_only( $updated ) { 160 | $term_id_params = array( 'sermon_related_series', 'sermon_related_speaker' ); 161 | foreach ( $term_id_params as $param ) { 162 | if ( isset( $updated[ $param ], $updated[ $param ]['id'] ) ) { 163 | if ( isset( $updated[ $param ]['name'] ) && 'this' === $updated[ $param ]['name'] ) { 164 | $updated[ $param ] = $updated[ $param ]['name']; 165 | } else { 166 | $updated[ $param ] = $updated[ $param ]['id']; 167 | } 168 | } 169 | } 170 | 171 | return $updated; 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /includes/shortcodes/shortcodes-sermons/class-run.php: -------------------------------------------------------------------------------- 1 | 10, // Will use WP's per-page option. 24 | 'content' => 'excerpt', 25 | 'remove_thumbnail' => false, 26 | 'thumbnail_size' => 'medium', 27 | 'number_columns' => 2, 28 | 'list_offset' => 0, 29 | 'wrap_classes' => '', 30 | 'remove_pagination' => false, 31 | 'related_speaker' => 0, 32 | 'related_series' => 0, 33 | ); 34 | 35 | /** 36 | * GCS_Sermons object 37 | * 38 | * @var GCS_Sermons 39 | * @since 0.1.0 40 | */ 41 | public $taxonomies; 42 | 43 | /** 44 | * Keep track of the levels of inception. 45 | * 46 | * @var string 47 | * @since 0.1.5 48 | */ 49 | protected static $inception_levels = 0; 50 | 51 | /** 52 | * Constructor 53 | * 54 | * @since 0.1.3 55 | * 56 | * @param GCS_Sermons $sermons 57 | * @param GCS_Taxonomies $taxonomies 58 | */ 59 | public function __construct( GCS_Sermons $sermons, GCS_Taxonomies $taxonomies ) { 60 | $this->taxonomies = $taxonomies; 61 | parent::__construct( $sermons ); 62 | } 63 | 64 | /** 65 | * Shortcode Output 66 | */ 67 | public function shortcode() { 68 | /* 69 | * Because it's possible to trigger inception, we need to keep track which 70 | * level we are in, and reset the shortcode object accordingly. 71 | * 72 | * Clever alert. The ++ happens AFTER the value is read, So $my_level starts at 0. 73 | */ 74 | $my_level = self::$inception_levels++; 75 | 76 | $args = $this->map_related_term_args( $this->get_initial_query_args() ); 77 | 78 | if ( ! $args ) { 79 | // We failed the related term check. 80 | return ''; 81 | } 82 | 83 | if ( ! isset( $args['post__not_in'] ) && is_singular( $this->sermons->post_type() ) ) { 84 | $args['post__not_in'] = array( get_queried_object_id() ); 85 | } 86 | 87 | $sermons = $this->sermons->get_many( $args ); 88 | 89 | if ( ! $sermons->have_posts() ) { 90 | return ''; 91 | } 92 | 93 | $max = $sermons->max_num_pages; 94 | $sermons = $this->map_sermon_args( $sermons, $my_level ); 95 | 96 | $content = ''; 97 | if ( 0 === $my_level ) { 98 | $content .= GCS_Style_Loader::get_template( 'list-item-style' ); 99 | } 100 | 101 | $args = $this->get_pagination( $max ); 102 | $args['wrap_classes'] = $this->get_wrap_classes(); 103 | $args['sermons'] = $sermons; 104 | 105 | $content .= GCS_Template_Loader::get_template( 'sermons-list', $args ); 106 | 107 | return $content; 108 | } 109 | 110 | public function get_initial_query_args() { 111 | $posts_per_page = (int) $this->att( 'per_page', get_option( 'posts_per_page' ) ); 112 | $paged = (int) get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1; 113 | $offset = ( ( $paged - 1 ) * $posts_per_page ) + $this->att( 'list_offset', 0 ); 114 | 115 | return compact( 'posts_per_page', 'paged', 'offset' ); 116 | } 117 | 118 | protected function map_related_term_args( $args ) { 119 | 120 | $required = false; 121 | $passes = false; 122 | $keys = array( 123 | 'series' => 'related_series', 124 | 'speaker' => 'related_speaker', 125 | ); 126 | 127 | foreach ( $keys as $key => $param ) { 128 | 129 | if ( $term_id = absint( $this->att( $param ) ) ) { 130 | 131 | $args['tax_query'][] = array( 132 | 'taxonomy' => $this->taxonomies->{$key}->taxonomy(), 133 | 'field' => 'id', 134 | 'terms' => $term_id, 135 | ); 136 | 137 | continue; 138 | } 139 | 140 | if ( 'this' !== $this->att( $param ) ) { 141 | continue; 142 | } 143 | 144 | $required = true; 145 | 146 | try { 147 | $sermon = gc_get_sermon_post( get_queried_object(), true ); 148 | 149 | $args['post__not_in'] = array( $sermon->ID ); 150 | 151 | $method = 'get_' . $key; 152 | $term = $sermon->$method(); 153 | 154 | if ( ! $term ) { 155 | throw new Exception( 'No '. $key . ' term.' ); 156 | } 157 | 158 | } catch( Exception $e ) { 159 | continue; 160 | } 161 | 162 | $passes = true; 163 | 164 | $args['tax_query'][] = array( 165 | 'taxonomy' => $this->taxonomies->{$key}->taxonomy(), 166 | 'field' => 'id', 167 | 'terms' => $term->term_id, 168 | ); 169 | 170 | } 171 | 172 | if ( $required && ! $passes ) { 173 | // They wanted sermons associated to 'this', but that's not possible. 174 | return false; 175 | } 176 | 177 | return $args; 178 | } 179 | 180 | protected function get_pagination( $total_pages ) { 181 | $nav = array( 'prev_link' => '', 'next_link' => '' ); 182 | 183 | if ( ! $this->bool_att( 'remove_pagination' ) ) { 184 | $nav['prev_link'] = get_previous_posts_link( __( ' Newer', 'gc-sermons' ), $total_pages ); 185 | $nav['next_link'] = get_next_posts_link( __( 'Older ', 'gc-sermons' ), $total_pages ); 186 | } 187 | 188 | return $nav; 189 | } 190 | 191 | protected function get_wrap_classes() { 192 | $columns = absint( $this->att( 'number_columns' ) ); 193 | $columns = $columns < 1 ? 1 : $columns; 194 | 195 | return $this->att( 'wrap_classes' ) . ' gc-' . $columns . '-cols gc-sermons-wrap'; 196 | } 197 | 198 | protected function map_sermon_args( $all_sermons, $my_level ) { 199 | global $post; 200 | $sermons = array(); 201 | 202 | $do_thumb = ! $this->bool_att( 'remove_thumbnail' ); 203 | $do_content = $this->bool_att( 'content' ); 204 | $type_of_content = $this->att( 'content' ); 205 | $thumb_size = $this->att( 'thumbnail_size' ); 206 | 207 | while ( $all_sermons->have_posts() ) { 208 | $all_sermons->the_post(); 209 | 210 | $obj = $all_sermons->post; 211 | 212 | $sermon = array(); 213 | $sermon['url'] = $obj->permalink(); 214 | $sermon['name'] = $obj->title(); 215 | $sermon['image'] = $do_thumb ? $obj->featured_image( $thumb_size ) : ''; 216 | $sermon['do_image'] = (bool) $sermon['image']; 217 | $sermon['description'] = ''; 218 | $sermon['do_description'] = $do_content; 219 | if ( $do_content ) { 220 | $sermon['description'] = 'excerpt' === $type_of_content 221 | ? $obj->loop_excerpt() 222 | : apply_filters( 'the_content', $obj->post_content ); 223 | } 224 | 225 | $sermons[] = $sermon; 226 | } 227 | 228 | wp_reset_postdata(); 229 | 230 | if ( $do_content ) { 231 | /* 232 | * Reset shortcode_object as well, as calling the content/excerpt 233 | * could trigger inception and change the object under us. 234 | */ 235 | $this->shortcode_object = WDS_Shortcode_Instances::get( $this->shortcode, $my_level ); 236 | } 237 | 238 | return $sermons; 239 | } 240 | 241 | } 242 | -------------------------------------------------------------------------------- /includes/class-template-loader.php: -------------------------------------------------------------------------------- 1 | template = "{$template}{$this->extension}"; 65 | 66 | if ( is_array( $name ) ) { 67 | $this->args = $name; 68 | } else { 69 | $this->args = $args; 70 | 71 | $name = (string) $name; 72 | if ( '' !== $name ) { 73 | $this->templates[] = $this->template = "{$template}-{$name}{$this->extension}"; 74 | } 75 | } 76 | 77 | $this->templates[] = $file; 78 | } 79 | 80 | /** 81 | * Loads the view and outputs it 82 | * 83 | * @since 0.1.3 84 | * 85 | * @param boolean $echo Whether to output or return the template 86 | * 87 | * @return string Rendered template 88 | */ 89 | public function load( $echo = false ) { 90 | $template = $this->locate_template(); 91 | 92 | // No template found. 93 | if ( ! $template ) { 94 | return; 95 | } 96 | 97 | // Filter args before outputting template. 98 | $this->args = apply_filters( "template_args_for_{$this->template}", $this->args, $this ); 99 | 100 | try { 101 | ob_start(); 102 | // Do html 103 | include $template; 104 | // grab the data from the output buffer and add it to our $content variable 105 | $content = ob_get_clean(); 106 | } catch ( Exception $e ) { 107 | wpdie( $e->getMessage() ); 108 | } 109 | 110 | $content = apply_filters( "template_output_for_{$this->template}", $content, $this ); 111 | 112 | if ( ! $echo ) { 113 | return $content; 114 | } 115 | 116 | echo $content; 117 | } 118 | 119 | /** 120 | * Retrieve the name of the highest priority template file that exists. 121 | * 122 | * Searches in the STYLESHEETPATH before TEMPLATEPATH and then this plugin's /templates 123 | * so that themes which inherit from a parent theme can just overload one file. 124 | * 125 | * @since 0.1.3 126 | * 127 | * @return string The located template filename. 128 | */ 129 | protected function locate_template() { 130 | $located = ''; 131 | 132 | foreach ( $this->templates as $template ) { 133 | if ( $located = $this->_locate( $template ) ) { 134 | return $located; 135 | } 136 | } 137 | 138 | return $located; 139 | } 140 | 141 | /** 142 | * Searches for template in 1) child theme, 2) parent theme, 3) this plugin. 143 | * 144 | * @since 0.1.3 145 | * 146 | * @param string $template Template file to search for. 147 | * 148 | * @return void 149 | */ 150 | protected function _locate( $template ) { 151 | $theme_file_path = '/gc-sermons/' . $template; 152 | 153 | $locations = apply_filters( "template_locations_for_{$this->template}", array( 154 | STYLESHEETPATH . '/gc-sermons/', 155 | TEMPLATEPATH . '/gc-sermons/', 156 | GC_Sermons_Plugin::$path . 'templates/', 157 | ), $this ); 158 | 159 | $located = ''; 160 | foreach ( $locations as $location ) { 161 | if ( file_exists( $location . $template ) ) { 162 | $located = $location . $template; 163 | break; 164 | } 165 | } 166 | 167 | return $located; 168 | } 169 | 170 | /** 171 | * Get one of the $args values. 172 | * 173 | * @since 0.1.3 174 | * 175 | * @param string $arg The $args key. 176 | * @param mixed $default Mixed value. 177 | * 178 | * @return mixed Value or default. 179 | */ 180 | public function get( $arg, $default = null ) { 181 | if ( isset( $this->args[ $arg ] ) ) { 182 | return $this->args[ $arg ]; 183 | } 184 | 185 | return $default; 186 | } 187 | 188 | /** 189 | * Output one of the $args values. 190 | * 191 | * @since 0.1.3 192 | * 193 | * @param string $arg The $args key. 194 | * @param mixed $esc_cb An escaping function callback. 195 | * @param mixed $default Mixed value. 196 | * 197 | * @return mixed Value or default. 198 | */ 199 | public function output( $arg, $esc_cb = '', $default = null ) { 200 | $val = $this->get( $arg, $default ); 201 | 202 | echo $esc_cb ? $esc_cb( $val ) : $val; 203 | } 204 | 205 | /** 206 | * Conditionally output one of the $args values, 207 | * if the value (or another one specified) exists. 208 | * 209 | * @since 0.1.3 210 | * 211 | * @param string $arg The $args key. 212 | * @param mixed $esc_cb An escaping function callback. 213 | * @param mixed $arg_to_check Alternate arg to check instead of $arg. 214 | * 215 | * @return mixed Value if condition is met. 216 | */ 217 | public function maybe_output( $arg, $esc_cb = '', $arg_to_check = null ) { 218 | $arg_to_check = null === $arg_to_check ? $arg : $arg_to_check; 219 | 220 | if ( $this->get( $arg_to_check ) ) { 221 | $this->output( $arg, $esc_cb ); 222 | } 223 | } 224 | 225 | /** 226 | * Magic method to fetch the rendered view when calling the call as a string. 227 | * 228 | * @since 0.1.3 229 | * 230 | * @return string Rendered template's HTML output. 231 | */ 232 | public function __toString() { 233 | return $this->load(); 234 | } 235 | 236 | /** 237 | * Get a rendered HTML view with the given arguments and return the view's contents. 238 | * 239 | * @since 0.1.3 240 | * 241 | * @param string $template The template file name, relative to the includes/templates/ folder 242 | * - without .php extension 243 | * @param string $name The name of the specialised template. If array, will take the place of the $args. 244 | * @param array $args An array of arguments to extract as variables into the template 245 | * 246 | * @return string Rendered template output 247 | */ 248 | public static function get_template( $template, $name = null, array $args = array() ) { 249 | $view = new self( $template, $name, $args ); 250 | return $view->load(); 251 | } 252 | 253 | /** 254 | * Render an HTML view with the given arguments and output the view's contents. 255 | * 256 | * @since 0.1.3 257 | * 258 | * @param string $template The template file name, relative to the includes/templates/ folder 259 | * - without .php extension 260 | * @param string $name The name of the specialised template. If array, will take the place of the $args. 261 | * @param array $args An array of arguments to extract as variables into the template 262 | * 263 | * @return void 264 | */ 265 | public static function output_template( $template, $name = null, array $args = array() ) { 266 | $view = new self( $template, $name, $args ); 267 | $view->load( 1 ); 268 | } 269 | 270 | } 271 | -------------------------------------------------------------------------------- /includes/taxonomies/class-speaker.php: -------------------------------------------------------------------------------- 1 | array( __( 'Speaker', 'gc-sermons' ), __( 'Speakers', 'gc-sermons' ), 'gcs-speaker' ), 36 | 'args' => array( 37 | 'hierarchical' => false, 38 | 'rewrite' => array( 'slug' => 'speaker' ), 39 | ), 40 | ) ); 41 | } 42 | 43 | /** 44 | * Initiate our hooks 45 | * 46 | * @since 0.1.0 47 | * @return void 48 | */ 49 | public function hooks() { 50 | add_action( 'cmb2_admin_init', array( $this, 'fields' ) ); 51 | } 52 | 53 | /** 54 | * Add custom fields to the CPT 55 | * 56 | * @since 0.1.0 57 | * @return void 58 | */ 59 | public function fields() { 60 | $fields = array( 61 | 'gc_sermon_speaker_connected_user' => array( 62 | 'name' => __( 'Connected User', 'gc-sermons' ), 63 | 'id' => 'gc_sermon_speaker_connected_user', 64 | 'desc' => __( 'Type the name of the WordPress user and select from the suggested options. By associating a speaker with a WordPress user, that WordPress user account details (first/last name, avatar, bio, etc) will be used as a fallback to the information here.', 'gc-sermons' ), 65 | 'type' => 'user_select_text', 66 | 'options' => array( 67 | 'minimum_user_level' => 0, 68 | ), 69 | ), 70 | $this->image_meta_key => array( 71 | 'name' => __( 'Speaker Avatar', 'gc-sermons' ), 72 | 'desc' => __( 'Select the speaker\'s avatar. Will only show if "Connected User" is not chosen, or if the "Connected User" does not have an avatar.', 'gc-sermons' ), 73 | 'id' => $this->image_meta_key, 74 | 'type' => 'file' 75 | ), 76 | ); 77 | 78 | $this->add_image_column( __( 'Speaker Avatar', 'gc-sermons' ) ); 79 | 80 | if ( function_exists( 'gc_staff' ) ) { 81 | unset( $fields['gc_sermon_speaker_connected_user'] ); 82 | 83 | $staff = gc_staff()->staff; 84 | $name = $staff->post_type( 'singular' ); 85 | 86 | $fields['gc_sermon_speaker_connected_staff'] = array( 87 | 'name' => sprintf( __( 'Connected %s', 'gc-sermons' ), $name ), 88 | 'id' => 'gc_sermon_speaker_connected_staff', 89 | 'desc' => sprintf( __( 'Type the name of the %1$s and select from the suggested options. By associating a speaker with a %1$s, that %1$s account details (first/last name, image, description, etc) will be used as a fallback to the information here.', 'gc-sermons' ), $name ), 90 | 'type' => 'post_search_text', 91 | 'post_type' => $staff->post_type(), 92 | 'select_type' => 'radio', 93 | 'select_behavior' => 'replace', 94 | ); 95 | 96 | } 97 | $cmb = $this->new_cmb2( array( 98 | 'id' => 'gc_sermon_speaker_metabox', 99 | 'taxonomies' => array( $this->taxonomy() ), // Tells CMB2 which taxonomies should 100 | 'object_types' => array( 'term' ), // Tells CMB2 to use term_meta vs post_meta 101 | 'fields' => $fields, 102 | ) ); 103 | } 104 | 105 | /** 106 | * Sets extra term data on the the term object, including the image and connected user object. 107 | * 108 | * @since 0.1.1 109 | * 110 | * @param WP_Term $term Term object 111 | * @param array $args Array of arguments. 112 | * 113 | * @return WP_Term|false 114 | */ 115 | protected function extra_term_data( $term, $args ) { 116 | $term->connected_user = $term->connected_staff = null; 117 | $term->nickname = ''; 118 | 119 | if ( function_exists( 'gc_staff' ) ) { 120 | if ( $connected_staff_id = get_term_meta( $term->term_id, 'gc_sermon_speaker_connected_staff', 1 ) ) { 121 | $term = $this->add_image( $term, $args['image_size'] ); 122 | $term = $this->augment_speaker_info_with_staff_info( $term, $connected_staff_id, $args ); 123 | } 124 | } else { 125 | if ( 126 | ( $connected_user = get_term_meta( $term->term_id, 'gc_sermon_speaker_connected_user', 1 ) ) 127 | && isset( $connected_user['id'] ) 128 | ) { 129 | $term = $this->augment_speaker_info( $term, $connected_user['id'], $args ); 130 | $term = $this->maybe_use_avatar( $term, $args ); 131 | } 132 | } 133 | 134 | // If not connected user, do the default setting 135 | if ( ! $term->connected_user || ! $term->connected_staff || ! isset( $term->image_url ) ) { 136 | $term = parent::extra_term_data( $term, $args ); 137 | } 138 | 139 | return $term; 140 | } 141 | 142 | /** 143 | * Takes a user ID and augments a speaker term object with user data. 144 | * 145 | * @since 0.1.1 146 | * 147 | * @param WP_Term $speaker Speaker term object. 148 | * @param int $user_id Connected user ID. 149 | * @param array $args Array of arguments. 150 | * 151 | * @return WP_Term Augmented term object. 152 | */ 153 | protected function augment_speaker_info( $speaker, $user_id, $args ) { 154 | if ( ! $user_id ) { 155 | return $speaker; 156 | } 157 | 158 | $user = get_userdata( $user_id ); 159 | 160 | if ( ! $user ) { 161 | return $speaker; 162 | } 163 | 164 | $speaker->connected_user = $user->data; 165 | $speaker->user_link = get_author_posts_url( $user->ID ); 166 | 167 | // Fallback to user description 168 | if ( ! $speaker->description && ( $user_desc = $user->get( 'description' ) ) ) { 169 | $speaker->description = $user_desc; 170 | } 171 | 172 | // Override speaker name with user name 173 | if ( $first = $user->get( 'first_name' ) ) { 174 | $speaker->name = $first; 175 | if ( $last = $user->get( 'last_name' ) ) { 176 | $speaker->name .= ' ' . $last; 177 | } 178 | } 179 | 180 | // Add speaker nickname 181 | $speaker->nickname = $user->get( 'nickname' ); 182 | 183 | return $speaker; 184 | } 185 | 186 | public function maybe_use_avatar( $speaker, $args = array() ) { 187 | $speaker = $this->add_image( $speaker, $args['image_size'] ); 188 | 189 | if ( isset( $speaker->connected_user ) ) { 190 | if ( ! $speaker->image ) { 191 | // Add avatar 192 | $speaker->image = get_avatar( $speaker->connected_user->ID, $args['image_size'], '', $speaker->name ); 193 | } 194 | 195 | if ( ! $speaker->image_url ) { 196 | $speaker->image_url = get_avatar_url( $speaker->connected_user->ID, array( 197 | 'size' => $args['image_size'], 198 | ) ); 199 | } 200 | } 201 | 202 | return $speaker; 203 | } 204 | 205 | /** 206 | * Takes a staff member post ID and augments a speaker term object with staff data. 207 | * 208 | * @since 0.1.1 209 | * 210 | * @param WP_Term $speaker Speaker term object. 211 | * @param int $connected_staff_id Connected staff member post ID. 212 | * @param array $args Array of arguments. 213 | * 214 | * @return WP_Term Augmented term object. 215 | */ 216 | protected function augment_speaker_info_with_staff_info( $speaker, $connected_staff_id, $args ) { 217 | if ( ! $connected_staff_id ) { 218 | return $speaker; 219 | } 220 | 221 | $staff = get_post( $connected_staff_id ); 222 | 223 | if ( ! $staff || ! isset( $staff->ID ) ) { 224 | return $speaker; 225 | } 226 | 227 | $speaker->connected_staff = $staff = new GCST_Staff_Member( $staff ); 228 | 229 | if ( 230 | ( $connected_user = $staff->get_meta( 'gc_staff_connected_user' ) ) 231 | && isset( $connected_user['id'] ) 232 | ) { 233 | $speaker = $this->augment_speaker_info( $speaker, $connected_user['id'], $args ); 234 | } 235 | 236 | $speaker->user_link = $staff->permalink(); 237 | 238 | // Fallback to staff description 239 | if ( ! $speaker->description && $staff->post_content ) { 240 | $speaker->description = $staff->post_content; 241 | } 242 | 243 | // Override speaker name with user name 244 | if ( $first = $staff->get_meta( 'gc_staff_first' ) ) { 245 | $speaker->name = $first; 246 | if ( $last = $staff->get_meta( 'gc_staff_last' ) ) { 247 | $speaker->name .= ' ' . $last; 248 | } 249 | } 250 | 251 | if ( ! $speaker->image ) { 252 | $speaker->image = $staff->featured_image( $args['image_size'] ); 253 | } 254 | 255 | if ( ! $speaker->image_url ) { 256 | $src = wp_get_attachment_image_src( $staff->image_id(), $args['image_size'] ); 257 | $speaker->image_url = isset( $src[0] ) ? $src[0] : ''; 258 | } 259 | 260 | return $speaker; 261 | } 262 | 263 | } 264 | -------------------------------------------------------------------------------- /gc-sermons.php: -------------------------------------------------------------------------------- 1 | sermons = new GCS_Sermons( $this ); 174 | $this->taxonomies = new GCS_Taxonomies( $this->sermons ); 175 | $this->async = new GCS_Async( $this ); 176 | $this->shortcodes = new GCS_Shortcodes( $this ); 177 | } // END OF PLUGIN CLASSES FUNCTION 178 | 179 | /** 180 | * Add hooks and filters 181 | * 182 | * @since 0.1.0 183 | * @return void 184 | */ 185 | public function hooks() { 186 | if ( ! defined( 'CMB2_LOADED' ) || ! defined( 'WDS_SHORTCODES_LOADED' ) ) { 187 | add_action( 'tgmpa_register', array( $this, 'register_required_plugin' ) ); 188 | } else { 189 | add_action( 'init', array( $this, 'init' ) ); 190 | $this->plugin_classes(); 191 | } 192 | } 193 | 194 | /** 195 | * Requires CMB2 to be installed 196 | */ 197 | public function register_required_plugin() { 198 | 199 | $plugins = array( 200 | array( 201 | 'name' => 'CMB2', 202 | 'slug' => 'cmb2', 203 | 'required' => true, 204 | 'version' => '2.2.1', 205 | ), 206 | ); 207 | 208 | $config = array( 209 | 'domain' => 'gc-sermons', 210 | 'parent_slug' => 'plugins.php', 211 | 'capability' => 'install_plugins', 212 | 'menu' => 'install-required-plugins', 213 | 'has_notices' => true, 214 | 'is_automatic' => true, 215 | 'message' => '', 216 | 'strings' => array( 217 | 'page_title' => __( 'Install Required Plugins', 'cool-shortcode' ), 218 | 'menu_title' => __( 'Install Plugins', 'cool-shortcode' ), 219 | 'installing' => __( 'Installing Plugin: %s', 'cool-shortcode' ), 220 | // %1$s = plugin name 221 | 'oops' => __( 'Something went wrong with the plugin API.', 'cool-shortcode' ), 222 | 'notice_can_install_required' => _n_noop( 'The "WDS Shortcodes" plugin requires the following plugin: %1$s.', 'This plugin requires the following plugins: %1$s.' ), 223 | // %1$s = plugin name(s) 224 | 'notice_can_install_recommended' => _n_noop( 'This plugin recommends the following plugin: %1$s.', 'This plugin recommends the following plugins: %1$s.' ), 225 | // %1$s = plugin name(s) 226 | 'notice_cannot_install' => _n_noop( 'Sorry, but you do not have the correct permissions to install the %s plugin. Contact the administrator of this site for help on getting the plugin installed.', 'Sorry, but you do not have the correct permissions to install the %s plugins. Contact the administrator of this site for help on getting the plugins installed.' ), 227 | // %1$s = plugin name(s) 228 | 'notice_can_activate_required' => _n_noop( 'The following required plugin is currently inactive: %1$s.', 'The following required plugins are currently inactive: %1$s.' ), 229 | // %1$s = plugin name(s) 230 | 'notice_can_activate_recommended' => _n_noop( 'The following recommended plugin is currently inactive: %1$s.', 'The following recommended plugins are currently inactive: %1$s.' ), 231 | // %1$s = plugin name(s) 232 | 'notice_cannot_activate' => _n_noop( 'Sorry, but you do not have the correct permissions to activate the %s plugin. Contact the administrator of this site for help on getting the plugin activated.', 'Sorry, but you do not have the correct permissions to activate the %s plugins. Contact the administrator of this site for help on getting the plugins activated.' ), 233 | // %1$s = plugin name(s) 234 | 'notice_ask_to_update' => _n_noop( 'The following plugin needs to be updated to its latest version to ensure maximum compatibility with this plugin: %1$s.', 'The following plugins need to be updated to their latest version to ensure maximum compatibility with this plugin: %1$s.' ), 235 | // %1$s = plugin name(s) 236 | 'notice_cannot_update' => _n_noop( 'Sorry, but you do not have the correct permissions to update the %s plugin. Contact the administrator of this site for help on getting the plugin updated.', 'Sorry, but you do not have the correct permissions to update the %s plugins. Contact the administrator of this site for help on getting the plugins updated.' ), 237 | // %1$s = plugin name(s) 238 | 'install_link' => _n_noop( 'Begin installing plugin', 'Begin installing plugins' ), 239 | 'activate_link' => _n_noop( 'Activate installed plugin', 'Activate installed plugins' ), 240 | 'return' => __( 'Return to Required Plugins Installer', 'cool-shortcode' ), 241 | 'plugin_activated' => __( 'Plugin activated successfully.', 'cool-shortcode' ), 242 | 'complete' => __( 'All plugins installed and activated successfully. %s', 'cool-shortcode' ), 243 | // %1$s = dashboard link 244 | ), 245 | ); 246 | 247 | tgmpa( $plugins, $config ); 248 | } 249 | 250 | /** 251 | * Activate the plugin 252 | * 253 | * @since 0.1.0 254 | * @return void 255 | */ 256 | public static function activate() { 257 | self::get_instance(); 258 | flush_rewrite_rules(); 259 | } 260 | 261 | /** 262 | * Deactivate the plugin 263 | * Uninstall routines should be in uninstall.php 264 | * 265 | * @since 0.1.0 266 | * @return void 267 | */ 268 | public static function deactivate() { 269 | flush_rewrite_rules(); 270 | } 271 | 272 | /** 273 | * Init hooks 274 | * 275 | * @since 0.1.0 276 | * @return void 277 | */ 278 | public function init() { 279 | load_plugin_textdomain( 'gc-sermons', false, dirname( self::$basename ) . '/languages/' ); 280 | } 281 | 282 | /** 283 | * Magic getter for our object. 284 | * 285 | * @since 0.1.0 286 | * @param string $field Field to get. 287 | * @throws Exception Throws an exception if the field is invalid. 288 | * @return mixed 289 | */ 290 | public function __get( $field ) { 291 | switch ( $field ) { 292 | case 'version': 293 | return self::VERSION; 294 | case 'sermons': 295 | case 'taxonomies': 296 | case 'shortcodes': 297 | return $this->{$field}; 298 | case 'series': 299 | case 'speaker': 300 | case 'topic': 301 | case 'tag': 302 | case 'scripture': 303 | return $this->taxonomies->{$field}; 304 | default: 305 | throw new Exception( 'Invalid '. __CLASS__ .' property: ' . $field ); 306 | } 307 | } 308 | } 309 | 310 | /** 311 | * Grab the GC_Sermons_Plugin object and return it. 312 | * Wrapper for GC_Sermons_Plugin::get_instance() 313 | * 314 | * @since 0.1.0 315 | * @return GC_Sermons_Plugin Singleton instance of plugin class. 316 | */ 317 | function gc_sermons() { 318 | return GC_Sermons_Plugin::get_instance(); 319 | } 320 | 321 | // Kick it off. 322 | add_action( 'plugins_loaded', array( gc_sermons(), 'hooks' ) ); 323 | register_activation_hook( __FILE__, array( 'GC_Sermons_Plugin', 'activate' ) ); 324 | register_deactivation_hook( __FILE__, array( 'GC_Sermons_Plugin', 'deactivate' ) ); 325 | 326 | -------------------------------------------------------------------------------- /functions.php: -------------------------------------------------------------------------------- 1 | taxonomies->series->taxonomy() ) ? get_queried_object() : 0; 48 | } 49 | 50 | if ( $term ) { 51 | return gc_sermons()->taxonomies->series->get( $term, $args ); 52 | } 53 | 54 | return false; 55 | } 56 | 57 | /** 58 | * Gets a GCS_Speaker augmented term object from a term object or ID. 59 | * 60 | * @since 0.2.0 61 | * 62 | * @param mixed $term Term object or ID. 63 | * @param array $args Array of arguments. 64 | * 65 | * @return GCS_Speaker|false GCS_Speaker object if successful. 66 | */ 67 | function gc_get_speaker_object( $term = 0, $args = array() ) { 68 | if ( ! $term ) { 69 | $term = is_tax( gc_sermons()->taxonomies->speaker->taxonomy() ) ? get_queried_object() : 0; 70 | } 71 | 72 | if ( $term ) { 73 | return gc_sermons()->taxonomies->speaker->get( $term, $args ); 74 | } 75 | 76 | return false; 77 | } 78 | 79 | /** 80 | * Gets a GCS_Topic augmented term object from a term object or ID. 81 | * 82 | * @since 0.2.0 83 | * 84 | * @param mixed $term Term object or ID. 85 | * @param array $args Array of arguments. 86 | * 87 | * @return GCS_Topic|false GCS_Topic object if successful. 88 | */ 89 | function gc_get_topic_object( $term = 0, $args = array() ) { 90 | if ( ! $term ) { 91 | $term = is_tax( gc_sermons()->taxonomies->topic->taxonomy() ) ? get_queried_object() : 0; 92 | } 93 | 94 | if ( $term ) { 95 | return gc_sermons()->taxonomies->topic->get( $term, $args ); 96 | } 97 | 98 | return false; 99 | } 100 | 101 | /** 102 | * Gets a GCS_Tag augmented term object from a term object or ID. 103 | * 104 | * @since 0.2.0 105 | * 106 | * @param mixed $term Term object or ID. 107 | * @param array $args Array of arguments. 108 | * 109 | * @return GCS_Tag|false GCS_Tag object if successful. 110 | */ 111 | function gc_get_tag_object( $term = 0, $args = array() ) { 112 | if ( ! $term ) { 113 | $term = is_tax( gc_sermons()->taxonomies->tag->taxonomy() ) ? get_queried_object() : 0; 114 | } 115 | 116 | if ( $term ) { 117 | return gc_sermons()->taxonomies->tag->get( $term, $args ); 118 | } 119 | 120 | return false; 121 | } 122 | 123 | /** 124 | * Gets a GCS_Scripture augmented term object from a term object or ID. 125 | * 126 | * @since 0.2.0 127 | * 128 | * @param mixed $term Term object or ID. 129 | * @param array $args Array of arguments. 130 | * 131 | * @return GCS_Scripture|false GCS_Scripture object if successful. 132 | */ 133 | function gc_get_scripture_object( $term = 0, $args = array() ) { 134 | if ( ! $term ) { 135 | $term = is_tax( gc_sermons()->taxonomies->scripture->taxonomy() ) ? get_queried_object() : 0; 136 | } 137 | 138 | if ( $term ) { 139 | return gc_sermons()->taxonomies->scripture->get( $term, $args ); 140 | } 141 | 142 | return false; 143 | } 144 | 145 | /** 146 | * Get's info for a series attached to the sermon. 147 | * 148 | * @since 0.1.3 149 | * 150 | * @param mixed $sermon Post object or ID or (GCS_Sermon_Post object). 151 | * @param boolean $args Args array 152 | * @param array $get_series_args Args for GCS_Sermon_Post::get_series() 153 | * 154 | * @return string Sermon series info output. 155 | */ 156 | function gc_get_sermon_series_info( $sermon = 0, $args = array(), $get_series_args = array() ) { 157 | if ( ! ( $sermon = gc_get_sermon_post( $sermon ) ) ) { 158 | // If no sermon, bail. 159 | return ''; 160 | } 161 | 162 | $args = wp_parse_args( $args, array( 163 | 'remove_thumbnail' => false, 164 | 'remove_description' => true, 165 | 'thumbnail_size' => 'medium', 166 | 'wrap_classes' => '', 167 | ) ); 168 | 169 | $get_series_args['image_size'] = isset( $get_series_args['image_size'] ) 170 | ? $get_series_args['image_size'] 171 | : $args['thumbnail_size']; 172 | 173 | if ( ! ( $series = $sermon->get_series( $get_series_args ) ) ) { 174 | // If no series, bail. 175 | return ''; 176 | } 177 | 178 | $series->classes = $args['wrap_classes']; 179 | $series->do_image = ! $args['remove_thumbnail'] && $series->image; 180 | $series->do_description = ! $args['remove_description'] && $series->description; 181 | $series->url = $series->term_link; 182 | 183 | $content = ''; 184 | $content .= GCS_Style_Loader::get_template( 'list-item-style' ); 185 | $content .= GCS_Template_Loader::get_template( 'list-item', (array) $series ); 186 | 187 | // Not a list item. 188 | $content = str_replace( array( ' false, 212 | 'thumbnail_size' => 'medium', 213 | 'wrap_classes' => '', 214 | ) ); 215 | 216 | $get_speaker_args['image_size'] = isset( $get_speaker_args['image_size'] ) 217 | ? $get_speaker_args['image_size'] 218 | : $args['thumbnail_size']; 219 | 220 | if ( ! ( $speaker = $sermon->get_speaker( $get_speaker_args ) ) ) { 221 | // If no speaker, bail. 222 | return ''; 223 | } 224 | 225 | // If no sermon or no sermon speaker, bail. 226 | if ( ! $sermon || ! ( $speaker = $sermon->get_speaker( $get_speaker_args ) ) ) { 227 | return ''; 228 | } 229 | 230 | $speaker->image = ! $args['remove_thumbnail'] ? $speaker->image : ''; 231 | $speaker->classes = $args['wrap_classes']; 232 | 233 | $content = GCS_Template_Loader::get_template( 'sermon-speaker-info', (array) $speaker ); 234 | 235 | return $content; 236 | } 237 | 238 | /** 239 | * Get's related links output for the sermon. 240 | * 241 | * @since 0.1.3 242 | * 243 | * @param mixed $sermon Post object or ID or (GCS_Sermon_Post object). 244 | * 245 | * @return string Sermon related links output. 246 | */ 247 | function gc_get_sermon_related_links( $sermon = 0 ) { 248 | $sermon = gc_get_sermon_post( $sermon ); 249 | 250 | // If no sermon or no related links, bail. 251 | if ( ! $sermon || ! ( $links = $sermon->get_meta( 'gc_related_links' ) ) || ! is_array( $links ) ) { 252 | return ''; 253 | } 254 | 255 | $content = GCS_Template_Loader::get_template( 'related-links', array( 256 | 'title' => __( 'Related Links', 'gc-sermons' ), 257 | 'links' => $links, 258 | ) ); 259 | 260 | return $content; 261 | } 262 | 263 | /** 264 | * Get's video player for the sermon. 265 | * 266 | * @since 0.1.3 267 | * 268 | * @param mixed $sermon Post object or ID or (GCS_Sermon_Post object). 269 | * @param mixed $args Arguments passed to GCS_Sermon_Post::get_video_player(). 270 | * 271 | * @return string Sermon video player output. 272 | */ 273 | function gc_get_sermon_video_player( $sermon = 0, $args = array() ) { 274 | $sermon = gc_get_sermon_post( $sermon ); 275 | 276 | // If no sermon or no related links, bail. 277 | if ( ! $sermon || ! ( $video_player = $sermon->get_video_player( $args ) ) ) { 278 | return ''; 279 | } 280 | 281 | return $video_player; 282 | } 283 | 284 | /** 285 | * Get's audio player for the sermon. 286 | * 287 | * @since 0.1.3 288 | * 289 | * @param mixed $sermon Post object or ID or (GCS_Sermon_Post object). 290 | * @param mixed $args Arguments passed to GCS_Sermon_Post::get_audio_player(). 291 | * 292 | * @return string Sermon audio player output. 293 | */ 294 | function gc_get_sermon_audio_player( $sermon = 0, $args = array() ) { 295 | $sermon = gc_get_sermon_post( $sermon ); 296 | 297 | // If no sermon or no related links, bail. 298 | if ( ! $sermon || ! ( $audio_player = $sermon->get_audio_player( $args ) ) ) { 299 | return ''; 300 | } 301 | 302 | return $audio_player; 303 | } 304 | 305 | /** 306 | * Gets the next search results page link when using the search widget. 307 | * 308 | * @since 0.1.5 309 | * 310 | * @param int $total_pages Total number of pages. 311 | * 312 | * @return string Next results page link, if there is a next page. 313 | */ 314 | function gc_search_get_next_results_link( $total_pages ) { 315 | $page = absint( gc__get_arg( 'results-page', 1 ) ); 316 | $link = ''; 317 | 318 | if ( ++$page <= $total_pages ) { 319 | $link = sprintf( 320 | '%s', 321 | esc_url( add_query_arg( 'results-page', $page ) ), 322 | apply_filters( 'gc_next_results_page_link_attributes', '' ), 323 | __( 'Older ', 'gc-sermons' ) 324 | ); 325 | } 326 | 327 | return $link; 328 | } 329 | 330 | /** 331 | * Gets the previous search results page link when using the search widget. 332 | * 333 | * @since 0.1.5 334 | * 335 | * @return string Next results page link, if there is a previous page. 336 | */ 337 | function gc_search_get_previous_results_link() { 338 | $page = absint( gc__get_arg( 'results-page', 1 ) ); 339 | $link = ''; 340 | 341 | if ( $page-- > 1 ) { 342 | $url = $page > 1 ? add_query_arg( 'results-page', $page ) : remove_query_arg( 'results-page' ); 343 | $link = sprintf( 344 | '%s', 345 | esc_url( $url ), 346 | apply_filters( 'gc_previous_results_page_link_attributes', '' ), 347 | __( ' Newer', 'gc-sermons' ) 348 | ); 349 | } 350 | 351 | return $link; 352 | } 353 | 354 | /** 355 | * Helper function for getting $_GET values with optional default value. 356 | * 357 | * @since 0.1.5 358 | * 359 | * @param string $arg Query arg to check 360 | * @param mixed $default Optional default value. Defaults to null. 361 | * 362 | * @return mixed Result of query var or default. 363 | */ 364 | function gc__get_arg( $arg, $default = null ) { 365 | return isset( $_GET[ $arg ] ) ? $_GET[ $arg ] : $default; 366 | } 367 | -------------------------------------------------------------------------------- /includes/taxonomies/class-taxonomies-base.php: -------------------------------------------------------------------------------- 1 | 512, 41 | ); 42 | 43 | /** 44 | * The default args array for self::get_many() 45 | * 46 | * @var array 47 | * @since 0.1.1 48 | */ 49 | protected $term_get_many_args_defaults = array( 50 | 'orderby' => 'name', 51 | 'augment_terms' => true, 52 | ); 53 | 54 | /** 55 | * The image column title (if applicable). 56 | * 57 | * @var string 58 | * @since 0.1.3 59 | */ 60 | protected $img_col_title = ''; 61 | 62 | /** 63 | * Constructor 64 | * Register Taxonomy. See documentation in Taxonomy_Core, and in wp-includes/taxonomy.php 65 | * 66 | * @since 0.1.0 67 | * @param object $sermons GCS_Sermons object. 68 | * @return void 69 | */ 70 | public function __construct( $sermons, $args ) { 71 | $this->sermons = $sermons; 72 | $this->hooks(); 73 | 74 | $this->flush_cache = isset( $_GET['flush_cache'] ) && date( 'Y-m-d' ) === $_GET['flush_cache']; 75 | 76 | /* 77 | * Register this taxonomy 78 | * First parameter should be an array with Singular, Plural, and Registered name 79 | * Second parameter is the register taxonomy arguments 80 | * Third parameter is post types to attach to. 81 | */ 82 | parent::__construct( 83 | $args['labels'], 84 | $args['args'], 85 | array( $this->sermons->post_type() ) 86 | ); 87 | 88 | add_action( 'plugins_loaded', array( $this, 'filter_values' ), 'plugins_loaded' === current_filter() ? 12 : 4 ); 89 | add_action( 'wp_async_set_sermon_terms', array( $this, 'trigger_cache_flush' ), 10, 2 ); 90 | } 91 | 92 | /** 93 | * Filter values before taxonomy is officially registered. 94 | * 95 | * @since 0.1.0 96 | * 97 | * @return void 98 | */ 99 | public function filter_values() { 100 | $args = array( 101 | 'singular' => $this->singular, 102 | 'plural' => $this->plural, 103 | 'taxonomy' => $this->taxonomy, 104 | 'arg_overrides' => $this->arg_overrides, 105 | 'object_types' => $this->object_types, 106 | ); 107 | 108 | $filtered_args = apply_filters( 'gcs_taxonomies_'. $this->id, $args, $this ); 109 | if ( $filtered_args !== $args ) { 110 | foreach ( $args as $arg => $val ) { 111 | if ( isset( $filtered_args[ $arg ] ) ) { 112 | $this->{$arg} = $filtered_args[ $arg ]; 113 | } 114 | } 115 | } 116 | } 117 | 118 | /** Columns ***************************************************************/ 119 | 120 | /** 121 | * Register image columns for $this->taxonomy(). 122 | * 123 | * @todo Need to disable JJJ's term image stuff for this taxonomy. 124 | * https://twitter.com/Jtsternberg/status/735542428522971136 125 | * 126 | * @since 0.1.3 127 | * 128 | * @param string $img_col_title The title for the Image column. 129 | */ 130 | protected function add_image_column( $img_col_title ) { 131 | $this->img_col_title = $img_col_title ? $img_col_title : __( 'Image', 'gc-sermons' ); 132 | 133 | $tax = $this->taxonomy(); 134 | 135 | add_filter( "manage_edit-{$tax}_columns", array( $this, 'add_column_header' ) ); 136 | add_filter( "manage_{$tax}_custom_column", array( $this, 'add_column_value' ), 10, 3 ); 137 | } 138 | 139 | /** 140 | * Add the "tax-image" column to taxonomy terms list-tables. 141 | * 142 | * @since 0.1.3 143 | * 144 | * @param array $columns 145 | * 146 | * @return array 147 | */ 148 | public function add_column_header( $columns = array() ) { 149 | $columns['tax-image'] = $this->img_col_title; 150 | 151 | return $columns; 152 | } 153 | 154 | /** 155 | * Output the value for the custom column. 156 | * 157 | * @since 0.1.3 158 | * 159 | * @param string $empty 160 | * @param string $custom_column 161 | * @param int $term_id 162 | * 163 | * @return mixed 164 | */ 165 | public function add_column_value( $empty = '', $custom_column = '', $term_id = 0 ) { 166 | 167 | // Bail if no taxonomy passed or not on the `tax-image` column 168 | if ( empty( $_REQUEST['taxonomy'] ) || ( 'tax-image' !== $custom_column ) || ! empty( $empty ) ) { 169 | return; 170 | } 171 | 172 | $retval = '—'; 173 | 174 | // Get the term data. 175 | $term = $this->get( $term_id, array( 'image_size' => 'thumb' ) ); 176 | 177 | // Output image if not empty. 178 | if ( isset( $term->image_id ) && $term->image_id ) { 179 | $retval = wp_get_attachment_image( $term->image_id, 'thumb', false, array( 180 | 'style' => 'max-width:100%;height: auto;', 181 | ) ); 182 | 183 | $link = get_edit_term_link( $term->term_id, $this->taxonomy(), $this->sermons->post_type() ); 184 | 185 | if ( $link ) { 186 | $retval = ''. $retval .''; 187 | } 188 | } 189 | 190 | echo $retval; 191 | } 192 | 193 | /** Required by Extended Classes *****************************************/ 194 | 195 | /** 196 | * Initiate our hooks 197 | * 198 | * @since 0.1.0 199 | * @return void 200 | */ 201 | abstract function hooks(); 202 | 203 | /** Helper Methods *******************************************************/ 204 | 205 | public function new_cmb2( $args ) { 206 | $cmb_id = $args['id']; 207 | return new_cmb2_box( apply_filters( "gcs_cmb2_box_args_{$this->id}_{$cmb_id}", $args ) ); 208 | } 209 | 210 | /** 211 | * Retrieve the terms for the most recent post which has this taxonomy set. 212 | * 213 | * @since 0.1.0 214 | * 215 | * @param boolean $get_single_term Whether to get the first term or all of them. 216 | * 217 | * @return GCS_Sermon_Post|false GC Sermon post object if successful. 218 | */ 219 | public function most_recent( $get_single_term = false ) { 220 | static $terms = null; 221 | 222 | if ( null === $terms ) { 223 | $sermon = $this->most_recent_sermon(); 224 | 225 | if ( ! $sermon ) { 226 | $terms = false; 227 | return $terms; 228 | } 229 | 230 | $terms = $sermon->{$this->id}; 231 | $terms = $terms && $get_single_term && is_array( $terms ) ? array_shift( $terms ) : $terms; 232 | } 233 | 234 | return $terms; 235 | } 236 | 237 | /** 238 | * Retrieve the most recent sermon which has terms in this taxonomy. 239 | * 240 | * @since 0.2.0 241 | * 242 | * @return GCS_Sermon_Post|false GC Sermon post object if successful. 243 | */ 244 | public function most_recent_sermon() { 245 | return $this->sermons->most_recent_with_taxonomy( $this->id ); 246 | } 247 | 248 | /** 249 | * Wrapper for get_terms 250 | * 251 | * @since 0.1.1 252 | * 253 | * @param array $args Array of arguments (passed to get_terms). 254 | * @param array $single_term_args Array of arguments for GCS_Taxonomies_Base::get(). 255 | * 256 | * @return array|false Array of term objects or false 257 | */ 258 | public function get_many( $args = array(), $single_term_args = array() ) { 259 | $args = wp_parse_args( $args, $this->term_get_many_args_defaults ); 260 | $args = apply_filters( "gcs_get_{$this->id}_args", $args ); 261 | 262 | if ( isset( $args['orderby'] ) && 'sermon_date' === $args['orderby'] ) { 263 | $terms = $this->get_terms_in_sermon_date_order(); 264 | } else { 265 | $terms = self::get_terms( $this->taxonomy(), $args ); 266 | } 267 | 268 | if ( ! $terms || is_wp_error( $terms ) ) { 269 | return false; 270 | } 271 | 272 | if ( 273 | isset( $args['augment_terms'] ) 274 | && $args['augment_terms'] 275 | && ! empty( $terms ) 276 | // Don't augment for queries w/ greater than 100 terms, for perf. reasons. 277 | && 100 < count( $terms ) 278 | ) { 279 | foreach ( $terms as $key => $term ) { 280 | $terms[ $key ] = $this->get( $term, $single_term_args ); 281 | } 282 | } 283 | 284 | return $terms; 285 | } 286 | 287 | /** 288 | * Wrapper for get_terms that allows searching using a wildcard name. 289 | * 290 | * @since 0.1.5 291 | * 292 | * @param array $search_term The search term. 293 | * @param array $args Array of arguments for GCS_Taxonomies_Base::get_many(). 294 | * @param array $single_term_args Array of arguments for GCS_Taxonomies_Base::get(). 295 | * 296 | * @return array|false Array of term objects or false 297 | */ 298 | public function search( $search_term, $args = array(), $single_term_args = array() ) { 299 | $args = wp_parse_args( $args, array( 300 | 'name__like' => sanitize_text_field( $search_term ), 301 | 'hide_empty' => false, 302 | 'orderby' => 'term_id', 303 | 'order' => 'DESC', 304 | 'cache_domain' => 'gc_sermons_search_' . $this->id, 305 | ) ); 306 | 307 | return $this->get_many( $args, $single_term_args ); 308 | } 309 | 310 | /** 311 | * Get a single term object 312 | * 313 | * @since 0.1.1 314 | * 315 | * @param object|int $term Term id or object 316 | * @param array $args Array of arguments. 317 | * 318 | * @return WP_Term|false Term object or false 319 | */ 320 | public function get( $term, $args = array() ) { 321 | $term = isset( $term->term_id ) ? $term : get_term_by( 'id', $term, $this->taxonomy() ); 322 | if ( ! isset( $term->term_id ) ) { 323 | return false; 324 | } 325 | 326 | $args = wp_parse_args( $args, $this->term_get_args_defaults ); 327 | $args = apply_filters( "gcs_get_{$this->id}_single_args", $args, $term, $this ); 328 | 329 | $term->term_link = get_term_link( $term ); 330 | $term = $this->extra_term_data( $term, $args ); 331 | 332 | return $term; 333 | } 334 | 335 | /** 336 | * Sets extra term data on the the term object, including the image, if applicable 337 | * 338 | * @since 0.1.1 339 | * 340 | * @param WP_Term $term Term object 341 | * @param array $args Array of arguments. 342 | * 343 | * @return WP_Term|false 344 | */ 345 | protected function extra_term_data( $term, $args ) { 346 | if ( $this->image_meta_key ) { 347 | $term = $this->add_image( $term, $args['image_size'] ); 348 | } 349 | 350 | return $term; 351 | } 352 | 353 | /** 354 | * Add term's image 355 | * 356 | * @since 0.1.1 357 | * 358 | * @param WP_Term $term Term object 359 | * @param string $size Size of the image to retrieve 360 | * 361 | * @return mixed URL if successful or set 362 | */ 363 | protected function add_image( $term, $size = '' ) { 364 | if ( ! $this->image_meta_key ) { 365 | return $term; 366 | } 367 | 368 | $term->image_id = get_term_meta( $term->term_id, $this->image_meta_key . '_id', 1 ); 369 | if ( ! $term->image_id ) { 370 | 371 | $term->image_url = get_term_meta( $term->term_id, $this->image_meta_key, 1 ); 372 | 373 | $term->image = $term->image_url ? ''. $term->name .'' : ''; 374 | 375 | return $term; 376 | } 377 | 378 | if ( $size ) { 379 | $size = is_numeric( $size ) ? array( $size, $size ) : $size; 380 | } 381 | 382 | $term->image = wp_get_attachment_image( $term->image_id, $size ? $size : 'thumbnail' ); 383 | 384 | $src = wp_get_attachment_image_src( $term->image_id, $size ? $size : 'thumbnail' ); 385 | $term->image_url = isset( $src[0] ) ? $src[0] : ''; 386 | 387 | return $term; 388 | } 389 | 390 | /** 391 | * Gets terms in the sermon date order. Result is cached for a max. of a day. 392 | * 393 | * @since 0.1.1 394 | * 395 | * @param bool $flush_cache Whether to get fresh results (flush cache) 396 | * 397 | * @return mixed Array of terms on success 398 | */ 399 | protected function get_terms_in_sermon_date_order( $flush_cache = false ) { 400 | $this->flush_cache = $this->flush_cache || $flush_cache; 401 | 402 | $terms = get_transient( $this->id . '_in_sermon_date_order' ); 403 | 404 | if ( ! $terms || $this->flush_cache ) { 405 | $sermons = $this->sermons->get_many( array( 406 | 'posts_per_page' => 1000, 407 | 'cache_results' => false, 408 | ) ); 409 | 410 | $taxonomy = $this->taxonomy(); 411 | $terms = array(); 412 | if ( $sermons->have_posts() ) { 413 | foreach ( $sermons->posts as $post ) { 414 | $year = get_the_date( 'Y', $post ); 415 | if ( $post_terms = get_the_terms( $post, $taxonomy ) ) { 416 | foreach ( $post_terms as $term ) { 417 | if ( ! isset( $terms[ $term->term_id ] ) ) { 418 | $term->year = $year; 419 | $terms[ $term->term_id ] = $term; 420 | } 421 | } 422 | } 423 | } 424 | } 425 | 426 | set_transient( $this->id . '_in_sermon_date_order', $terms, DAY_IN_SECONDS ); 427 | } 428 | 429 | return $terms; 430 | } 431 | 432 | /** 433 | * Hooks into the wp_async_set_sermon_terms action, which is triggered when a post is saved. 434 | * 435 | * @since 0.1.1 436 | * 437 | * @param int $post_id Post ID 438 | * @param string $taxonomy Taxonomy 439 | */ 440 | public function trigger_cache_flush( $post_id, $taxonomy ) { 441 | if ( 442 | $this->taxonomy() !== $taxonomy 443 | || $this->sermons->post_type() !== get_post_type( $post_id ) 444 | ) { 445 | return; 446 | } 447 | 448 | $this->get_terms_in_sermon_date_order( 1 ); 449 | } 450 | 451 | /** 452 | * Wrapper for `get_terms` to account for changes in WP 4.5 where taxonomy 453 | * is expected as part of the arguments. 454 | * 455 | * @since 0.1.5 456 | * 457 | * @return mixed Array of terms on success 458 | */ 459 | protected static function get_terms( $taxonomy, $args = array() ) { 460 | unset( $args['augment_terms'] ); 461 | if ( version_compare( $GLOBALS['wp_version'], '4.5.0', '>=' ) ) { 462 | $args['taxonomy'] = $taxonomy; 463 | $terms = get_terms( $args ); 464 | } else { 465 | $terms = get_terms( $taxonomy, $args ); 466 | } 467 | 468 | return $terms; 469 | } 470 | 471 | /** 472 | * Magic getter for our object. Allows getting but not setting. 473 | * 474 | * @param string $field 475 | * @throws Exception Throws an exception if the field is invalid. 476 | * @return mixed 477 | */ 478 | public function __get( $field ) { 479 | switch ( $field ) { 480 | case 'id': 481 | return $this->id; 482 | default: 483 | throw new Exception( 'Invalid ' . __CLASS__ . ' property: ' . $field ); 484 | } 485 | } 486 | } 487 | -------------------------------------------------------------------------------- /includes/class-sermon-post.php: -------------------------------------------------------------------------------- 1 | sermons->post_type(); 94 | 95 | if ( $post->post_type !== $post_type ) { 96 | throw new Exception( 'Sorry, '. __CLASS__ .' expects a '. $post_type .' object.' ); 97 | } 98 | 99 | $this->post = $post; 100 | } 101 | 102 | /** 103 | * Initate the video/audio media object 104 | * 105 | * @since 0.1.0 106 | * 107 | * @return array Array of video/audio media info. 108 | */ 109 | protected function init_media() { 110 | $this->media = array( 111 | 'video' => array(), 112 | 'audio' => array(), 113 | ); 114 | $this->add_media_type( 'video' ); 115 | $this->add_media_type( 'audio' ); 116 | return $this->media; 117 | } 118 | 119 | /** 120 | * Add media info to the media array for $type 121 | * 122 | * @since 0.1.0 123 | * 124 | * @param string $type type of media 125 | */ 126 | protected function add_media_type( $type = 'video' ) { 127 | // Only audio/video allowed. 128 | $type = 'video' === $type ? $type : 'audio'; 129 | $media = false; 130 | 131 | if ( $media_url = get_post_meta( $this->ID, "gc_sermon_{$type}_url", 1 ) ) { 132 | $media = array( 133 | 'type' => 'url', 134 | 'value' => $media_url 135 | ); 136 | } elseif ( $media_src = get_post_meta( $this->ID, "gc_sermon_{$type}_src_id", 1 ) ) { 137 | $media = array( 138 | 'type' => 'attachment_id', 139 | 'value' => $media_src, 140 | 'attachment_url' => get_post_meta( $this->ID, "gc_sermon_{$type}_src", 1 ) 141 | ); 142 | } elseif ( $media_url = get_post_meta( $this->ID, "gc_sermon_{$type}_src", 1 ) ) { 143 | $media = array( 144 | 'type' => 'url', 145 | 'value' => $media_url, 146 | ); 147 | } 148 | 149 | if ( $media ) { 150 | $this->media[ $type ] = $media; 151 | } 152 | 153 | return $this; 154 | } 155 | 156 | /** 157 | * Wrapper for wp_oembed_get/wp_video_shortcode 158 | * 159 | * @since 0.1.1 160 | * 161 | * @param array $args Optional. Args are passed to either WP_Embed::shortcode, 162 | * or wp_video_shortcode. 163 | * @return mixed The video player if successful. 164 | */ 165 | public function get_video_player( $args = array() ) { 166 | global $wp_embed; 167 | 168 | $media = empty( $this->media ) ? $this->init_media() : $this->media; 169 | $video = isset( $media['video'] ) ? $media['video'] : array(); 170 | if ( ! isset( $video['type'] ) ) { 171 | return ''; 172 | } 173 | 174 | $video_url = ''; 175 | if ( 'url' === $video['type'] ) { 176 | $wp_embed->post_ID = $this->ID; 177 | $video_player = $wp_embed->shortcode( $args, $video['value'] ); 178 | } elseif ( 'attachment_id' === $video['type'] ) { 179 | 180 | $args['src'] = $video['attachment_url']; 181 | if ( $video_player = wp_video_shortcode( $args ) ) { 182 | $video_player = '
    ' . $video_player . '
    '; 183 | } 184 | } 185 | 186 | return $video_player; 187 | } 188 | 189 | /** 190 | * Wrapper for wp_audio_shortcode 191 | * 192 | * @since 0.1.1 193 | * 194 | * @return mixed The audio player if successful. 195 | */ 196 | public function get_audio_player() { 197 | // Lazy-load the media-getting 198 | if ( empty( $this->media ) ) { 199 | $this->init_media(); 200 | } 201 | 202 | $audio = $this->media['audio']; 203 | if ( ! isset( $audio['type'] ) ) { 204 | return ''; 205 | } 206 | 207 | $audio_url = ''; 208 | if ( 'url' === $audio['type'] ) { 209 | $audio_url = $audio['value']; 210 | } elseif ( 'attachment_id' === $audio['type'] ) { 211 | $audio_url = $audio['attachment_url']; 212 | } 213 | 214 | if ( $audio_player = wp_audio_shortcode( array( 'src' => $audio_url ) ) ) { 215 | $audio_player = '
    ' . $audio_player . '
    '; 216 | } 217 | 218 | return $audio_player; 219 | } 220 | 221 | /** 222 | * Wrapper for get_permalink. 223 | * 224 | * @since 0.1.1 225 | * 226 | * @return string Sermon post permalink. 227 | */ 228 | public function permalink() { 229 | return get_permalink( $this->ID ); 230 | } 231 | 232 | /** 233 | * Wrapper for get_the_title. 234 | * 235 | * @since 0.1.1 236 | * 237 | * @return string Sermon post title. 238 | */ 239 | public function title() { 240 | return get_the_title( $this->ID ); 241 | } 242 | 243 | /** 244 | * Wrapper for the_excerpt. Returns value. Must be used in loop. 245 | * 246 | * @since 0.1.3 247 | * 248 | * @return string Sermon post excerpt. 249 | */ 250 | public function loop_excerpt() { 251 | ob_start(); 252 | the_excerpt(); 253 | // grab the data from the output buffer and add it to our $content variable 254 | $excerpt = ob_get_clean(); 255 | 256 | return $excerpt; 257 | } 258 | 259 | /** 260 | * Wrapper for get_the_post_thumbnail which stores the results to the object 261 | * 262 | * @since 0.1.0 263 | * 264 | * @param string|array $size Optional. Image size to use. Accepts any valid image size, or 265 | * an array of width and height values in pixels (in that order). 266 | * Default 'full'. 267 | * @param string|array $attr Optional. Query string or array of attributes. Default empty. 268 | * @return string The post thumbnail image tag. 269 | */ 270 | public function featured_image( $size = 'full', $attr = '' ) { 271 | // Unique id for the passed-in attributes. 272 | $id = md5( $attr ); 273 | 274 | if ( ! isset( $attr['series_image_fallback'] ) || false !== $attr['series_image_fallback'] ) { 275 | $series_image_fallback = true; 276 | if ( isset( $attr['series_image_fallback'] ) ) { 277 | unset( $attr['series_image_fallback'] ); 278 | } 279 | } 280 | 281 | if ( isset( $this->images[ $size ] ) ) { 282 | // If we got it already, then send it back 283 | if ( isset( $this->images[ $size ][ $id ] ) ) { 284 | return $this->images[ $size ][ $id ]; 285 | } else { 286 | $this->images[ $size ][ $id ] = array(); 287 | } 288 | } else { 289 | $this->images[ $size ][ $id ] = array(); 290 | } 291 | 292 | $img = get_the_post_thumbnail( $this->ID, $size, $attr ); 293 | $this->images[ $size ][ $id ] = $img ? $img : $this->series_image( $size, $attr ); 294 | 295 | return $this->images[ $size ][ $id ]; 296 | } 297 | 298 | /** 299 | * Wrapper for get_post_thumbnail_id 300 | * 301 | * @since 0.1.0 302 | * 303 | * @return string|int Post thumbnail ID or empty string. 304 | */ 305 | public function featured_image_id() { 306 | return get_post_thumbnail_id( $this->ID ); 307 | } 308 | 309 | /** 310 | * Get the series image. 311 | * 312 | * @since 0.1.0 313 | * 314 | * @param string|array $size Optional. Image size to use. Accepts any valid image size, or 315 | * an array of width and height values in pixels (in that order). 316 | * Default 'full'. 317 | * @param string|array $attr Optional. Query string or array of attributes. Default empty. 318 | * @return string The series image tag. 319 | */ 320 | public function series_image( $size = 'full', $attr = '' ) { 321 | $args = array( 'image_size' => $size ); 322 | $series = $this->get_series( $args ); 323 | 324 | return $series->image; 325 | } 326 | 327 | /** 328 | * Get single speaker for this sermon 329 | * 330 | * @since 0.1.1 331 | * 332 | * @param array Args to pass to GCS_Taxonomies_Base::get() 333 | * 334 | * @return WP_Term|false Speaker term object. 335 | */ 336 | public function get_speaker( $args = array() ) { 337 | $speakers = $this->speakers(); 338 | if ( empty( $speakers ) ) { 339 | return false; 340 | } 341 | 342 | if ( null === $this->speaker ) { 343 | $this->speaker = gc_get_speaker_object( $speakers[0], $args ); 344 | } 345 | 346 | return $this->speaker; 347 | } 348 | 349 | /** 350 | * Get single series for this sermon 351 | * 352 | * @since 0.1.1 353 | * 354 | * @param array Args to pass to GCS_Taxonomies_Base::get() 355 | * 356 | * @return WP_Term|false Series term object. 357 | */ 358 | public function get_series( $args = array() ) { 359 | $series = $this->series(); 360 | if ( empty( $series ) ) { 361 | return false; 362 | } 363 | 364 | if ( null === $this->single_series ) { 365 | $this->single_series = gc_get_series_object( $series[0], $args ); 366 | } 367 | 368 | return $this->single_series; 369 | } 370 | 371 | /** 372 | * Get other sermons in the same series. 373 | * 374 | * @since 0.1.1 375 | * 376 | * @param array $args Array of WP_Query arguments. 377 | * 378 | * @return mixed WP_Query instance if successful. 379 | */ 380 | public function get_others_in_series( $args = array() ) { 381 | $series = $this->get_series(); 382 | if ( ! $series ) { 383 | return new WP_Error( 'no_series_for_sermon', __( 'There is no series associated with this sermon.', 'gc-sermons' ), $this->ID ); 384 | } 385 | 386 | $args = wp_parse_args( $args, array( 387 | 'post__not_in' => array( $this->ID ), 388 | 'posts_per_page' => 10, 389 | 'no_found_rows' => true, 390 | ) ); 391 | 392 | $args['tax_query'] = array( 393 | array( 394 | 'taxonomy' => $series->taxonomy, 395 | 'field' => 'slug', 396 | 'terms' => $series->slug, 397 | ), 398 | ); 399 | 400 | return gc_sermons()->sermons->get_many( $args ); 401 | } 402 | 403 | /** 404 | * Get other sermons by the same speaker. 405 | * 406 | * @since 0.1.1 407 | * 408 | * @param array $args Array of WP_Query arguments. 409 | * 410 | * @return mixed WP_Query instance if successful. 411 | */ 412 | public function get_others_by_speaker( $args = array() ) { 413 | $speaker = $this->get_speaker(); 414 | if ( ! $speaker ) { 415 | return new WP_Error( 'no_speaker_for_sermon', __( 'There is no speaker associated with this sermon.', 'gc-sermons' ), $this->ID ); 416 | } 417 | 418 | $args = wp_parse_args( $args, array( 419 | 'post__not_in' => array( $this->ID ), 420 | 'posts_per_page' => 10, 421 | 'no_found_rows' => true, 422 | ) ); 423 | 424 | $args['tax_query'] = array( 425 | array( 426 | 'taxonomy' => $speaker->taxonomy, 427 | 'field' => 'slug', 428 | 'terms' => $speaker->slug, 429 | ), 430 | ); 431 | 432 | return gc_sermons()->sermons->get_many( $args ); 433 | } 434 | 435 | /** 436 | * Wrapper for get_the_terms for the series taxonomy 437 | * 438 | * @since 0.1.0 439 | * 440 | * @return array Array of series terms 441 | */ 442 | public function series() { 443 | if ( empty( $this->series ) ) { 444 | $this->series = $this->init_taxonomy( 'series' ); 445 | } 446 | 447 | return $this->series; 448 | } 449 | 450 | /** 451 | * Wrapper for get_the_terms for the speaker taxonomy 452 | * 453 | * @since 0.1.0 454 | * 455 | * @return array Array of speaker terms 456 | */ 457 | public function speakers() { 458 | if ( empty( $this->speakers ) ) { 459 | $this->speakers = $this->init_taxonomy( 'speaker' ); 460 | } 461 | 462 | return $this->speakers; 463 | } 464 | 465 | /** 466 | * Wrapper for get_the_terms for the topic taxonomy 467 | * 468 | * @since 0.1.0 469 | * 470 | * @return array Array of topic terms 471 | */ 472 | public function topics() { 473 | if ( empty( $this->topics ) ) { 474 | $this->topics = $this->init_taxonomy( 'topic' ); 475 | } 476 | 477 | return $this->topics; 478 | } 479 | 480 | /** 481 | * Wrapper for get_the_terms for the tag taxonomy 482 | * 483 | * @since 0.1.0 484 | * 485 | * @return array Array of tag terms 486 | */ 487 | public function tags() { 488 | if ( empty( $this->tags ) ) { 489 | $this->tags = $this->init_taxonomy( 'tag' ); 490 | } 491 | 492 | return $this->tags; 493 | } 494 | 495 | /** 496 | * Wrapper for get_the_terms for the scripture taxonomy 497 | * 498 | * @since 0.1.0 499 | * 500 | * @return array Array of scripture terms 501 | */ 502 | public function scriptures() { 503 | if ( empty( $this->scriptures ) ) { 504 | $this->scriptures = $this->init_taxonomy( 'scripture' ); 505 | } 506 | 507 | return $this->scriptures; 508 | } 509 | 510 | /** 511 | * Initate the taxonomy. 512 | * 513 | * @since 0.1.0 514 | * 515 | * @param string $taxonomy Taxonomy to initiate 516 | * 517 | * @return array Array of terms for this taxonomy. 518 | */ 519 | protected function init_taxonomy( $taxonomy ) { 520 | $tax_slug = gc_sermons()->taxonomies->{$taxonomy}->taxonomy(); 521 | return get_the_terms( $this->ID, $tax_slug ); 522 | } 523 | 524 | /** 525 | * Wrapper for get_post_meta 526 | * 527 | * @since 0.1.1 528 | * 529 | * @param string $key Meta key 530 | * 531 | * @return mixed Value of post meta 532 | */ 533 | public function get_meta( $key ) { 534 | return get_post_meta( $this->ID, $key, 1 ); 535 | } 536 | 537 | /** 538 | * Magic getter for our object. 539 | * 540 | * @param string $property 541 | * @throws Exception Throws an exception if the field is invalid. 542 | * @return mixed 543 | */ 544 | public function __get( $property ) { 545 | $property = $this->translate_property( $property ); 546 | 547 | // Automate 548 | switch ( $property ) { 549 | case 'series': 550 | case 'speakers': 551 | case 'topics': 552 | case 'tags': 553 | case 'scriptures': 554 | return $this->{$property}(); 555 | case 'post': 556 | return $this->{$property}; 557 | case 'media': 558 | // Lazy-load the media-getting 559 | if ( empty( $this->media ) ) { 560 | return $this->init_media(); 561 | } 562 | return $this->media; 563 | default: 564 | // Check post object for property 565 | // In general, we'll avoid using same-named properties, 566 | // so the post object properties are always available. 567 | if ( isset( $this->post->{$property} ) ) { 568 | return $this->post->{$property}; 569 | } 570 | throw new Exception( 'Invalid ' . __CLASS__ . ' property: ' . $property ); 571 | } 572 | } 573 | 574 | /** 575 | * Magic isset checker for our object. 576 | * 577 | * @param string $property 578 | * @throws Exception Throws an exception if the field is invalid. 579 | * @return mixed 580 | */ 581 | public function __isset( $property ) { 582 | $property = $this->translate_property( $property ); 583 | 584 | // Automate 585 | switch ( $property ) { 586 | case 'series': 587 | case 'speakers': 588 | case 'topics': 589 | case 'tags': 590 | case 'scriptures': 591 | $terms = $this->{$property}(); 592 | return ! empty( $terms ); 593 | default: 594 | // Check post object for property 595 | // In general, we'll avoid using same-named properties, 596 | // so the post object properties are always available. 597 | return isset( $this->post->{$property} ); 598 | } 599 | } 600 | 601 | /** 602 | * Allow some variations on the object __getter 603 | * 604 | * @since NEXXT 605 | * 606 | * @param string $property Object property to fetch 607 | * 608 | * @return string Maybe-modified property name 609 | */ 610 | protected function translate_property( $property ) { 611 | // Translate 612 | switch ( $property ) { 613 | case 'speaker': 614 | $property = 'speakers'; 615 | break; 616 | case 'topic': 617 | $property = 'topics'; 618 | break; 619 | case 'tag': 620 | $property = 'tags'; 621 | break; 622 | case 'scripture': 623 | $property = 'scriptures'; 624 | break; 625 | } 626 | 627 | return $property; 628 | } 629 | 630 | } 631 | --------------------------------------------------------------------------------