Last active
September 20, 2017 22:35
-
-
Save jimboobrien/05e307b5d7722547970c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*****************************************************************************/ | |
/**************VISIONQUEST CUSTOM FUNCTIONS***********************/ | |
Use get_template_directory_uri() when working with theme | |
Use get_stylesheet_uri () when wrking with child theme | |
/******************************************************************************/ | |
/** | |
* Proper way to enqueue scripts and styles in header as of Mar 2016 | |
*/ | |
function my_theme_scripts() { | |
wp_enqueue_style( 'octane-main-style', get_stylesheet_uri() ); | |
wp_enqueue_style( 'bootstrap-style', get_template_directory_uri() . '/css/bootstrap.min.css' ); | |
/* animate.css */ | |
wp_register_style( 'animate-css', get_template_directory_uri() . '/css/animate.min.css', array(), '20120725', 'screen' ); | |
/* conditional enqueue javascript script based on page ID and has dependency on jquery */ | |
if(is_page( '129' ) ) wp_enqueue_script('packery_js', get_template_directory_uri() .'/js/packery.pkgd.js', array('jquery'), false, true); | |
} //end function | |
add_action( 'wp_enqueue_scripts', 'my_theme_scripts' ); | |
/** | |
* Proper way to enqueue JS and IE fixes as of Mar 2015 | |
*/ | |
function octane_bootstrap_js() { | |
/* loads scripts variable to dynamically load later */ | |
global $wp_scripts; | |
/* only loads it and prepares it for it to be dynamically added */ | |
wp_register_script( 'html5_shiv', 'https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js', '', '', false ); | |
wp_register_script( 'respond_js', 'https://oss.maxcdn.com/respond/1.4.2/respond.min.js', '', '', false ); | |
/* dynamically add scripts - for IE (example) */ | |
$wp_scripts->add_data('html5_shiv', 'conditional', 'lt IE 9'); | |
$wp_scripts->add_data('respond_js', 'conditional', 'lt IE 9'); | |
wp_enqueue_script( 'octane_custom_js', get_template_directory_uri() . '/js/octane-custom.js', array(), '', true ); | |
} //end function | |
add_action( 'wp_enqueue_scripts', 'octane_bootstrap_js' ); | |
/** | |
*Enables custom menus to be used with our theme | |
*/ | |
add_theme_support( 'menus'); | |
add_theme_support( 'post-thumbnails' ); | |
function register_theme_menus() { | |
register_nav_menus( | |
array( | |
'header-menu' => __( 'Header Menu' ) | |
) //end array | |
); //end register_nav_menu | |
} //end function | |
add_action( 'init', 'register_theme_menus' ); | |
/** | |
*Enables custom menus to be used with our theme | |
*/ | |
add_theme_support( 'menus'); | |
add_theme_support( 'post-thumbnails' ); | |
/* PAGINATION */ | |
if ( ! function_exists( 'my_pagination' ) ) : | |
function my_pagination() { | |
global $wp_query; | |
$big = 999999999; // need an unlikely integer | |
echo paginate_links( array( | |
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ), | |
'format' => '?paged=%#%', | |
'current' => max( 1, get_query_var('paged') ), | |
'total' => $wp_query->max_num_pages | |
) ); | |
} | |
endif; | |
/** | |
* Create Widgets | |
*/ | |
add_action( 'widgets_init', 'octane_widgets_init' ); | |
function octane_widgets_init() { | |
register_sidebar( array( | |
'name' => __( 'Page Sidebar', 'octane-bootstrap' ), | |
'id' => 'sidebar-1', | |
'description' => __( 'Widgets in this area will be shown on all posts and pages.', 'octane-bootstrap' ), | |
'before_widget' => '<li id="%1$s" class="widget %2$s">', | |
'after_widget' => '</li>', | |
'before_title' => '<h3 class="widgettitle">', | |
'after_title' => '</h3>', | |
)); | |
} | |
/* =============================================================================================== | |
============================ CUSTOM POST TYPE ================================================== | |
================================================================================================*/ | |
add_action( 'init', 'octane_cpt_init' ); | |
function octane_cpt_init() { | |
/*============================ | |
======= Portfolio Post Type ======== | |
============================*/ | |
$portfolio_labels = array( | |
'name' => _x('Portfolios', 'post type general name', 'octane-bootstrap'), | |
'singular_name' => _x('Portfolio', 'post type singular name', 'octane-bootstrap'), | |
'add_new' => _x('Add New', 'portfolio', 'octane-bootstrap'), | |
'add_new_item' => __('Add New Portfolio', 'octane-bootstrap'), | |
'edit_item' => __('Edit Portfolio', 'octane-bootstrap'), | |
'new_item' => __('New Portfolio', 'octane-bootstrap'), | |
'view_item' => __('View Portfolio', 'octane-bootstrap'), | |
'search_items' => __('Search Portfolio', 'octane-bootstrap'), | |
'not_found' => __('No portfolio found', 'octane-bootstrap'), | |
'not_found_in_trash' => __('No portfolio found in Trash', 'octane-bootstrap'), | |
'parent_item_colon' => '', | |
'menu_name' => 'Portfolio' | |
); | |
// Some arguments and in the last line 'supports', we say to WordPress what features are supported on the Project post type | |
$portfolio_args = array( | |
'labels' => $portfolio_labels, | |
'public' => true, | |
'publicly_queryable' => true, | |
'show_ui' => true, | |
'show_in_menu' => true, | |
'query_var' => true, | |
'rewrite' => true, | |
/* this is important to make it so that page-portfolio.php will show when used */ | |
'capability_type' => 'post', | |
'can_export' => true, | |
/* make sure has_archive is turned off if you plan on using page-portfolio.php */ | |
'has_archive' => false, | |
'hierarchical' => true, | |
'menu_position' => null, | |
/* include this line to use global categories */ | |
//'taxonomies' => array('category'), | |
'supports' => array('title','editor','author','thumbnail','excerpt','comments','custom-fields','page-attributes') | |
); | |
// We call this function to register the custom post type | |
register_post_type('portfolio',$portfolio_args); | |
/*============================ | |
======= Portfolio Taxonomy ======== | |
============================*/ | |
// Initialize Taxonomy Labels | |
$tax_labels = array( | |
'name' => _x( 'Categories', 'taxonomy general name', 'octane-bootstrap' ), | |
'singular_name' => _x( 'Cat', 'taxonomy singular name' , 'octane-bootstrap'), | |
'search_items' => __( 'Search Types' , 'octane-bootstrap'), | |
'all_items' => __( 'All Cats' , 'octane-bootstrap'), | |
'parent_item' => __( 'Parent Cats', 'octane-bootstrap' ), | |
'parent_item_colon' => __( 'Parent Cats:' , 'octane-bootstrap'), | |
'edit_item' => __( 'Edit Cats', 'octane-bootstrap' ), | |
'update_item' => __( 'Update Cats' , 'octane-bootstrap'), | |
'add_new_item' => __( 'Add New Cats', 'octane-bootstrap' ), | |
'new_item_name' => __( 'New Cats Name' , 'octane-bootstrap'), | |
); | |
// Register Custom Taxonomy | |
register_taxonomy('portcats',array('portfolio'), array( | |
'hierarchical' => true, // define whether to use a system like tags or categories | |
'labels' => $tax_labels, | |
'show_ui' => true, | |
'show_admin_column' => true, | |
'query_var' => true, | |
'rewrite' => array( 'slug' => 'portfolio' ), | |
)); | |
/*============================ | |
======= Portfolio TAGS ======== | |
============================*/ | |
// Add new taxonomy, NOT hierarchical (like tags) | |
$labels = array( | |
'name' => _x( 'Tags', 'taxonomy general name' ), | |
'singular_name' => _x( 'Tag', 'taxonomy singular name' ), | |
'search_items' => __( 'Search Tags' ), | |
'popular_items' => __( 'Popular Tags' ), | |
'all_items' => __( 'All Tags' ), | |
'parent_item' => null, | |
'parent_item_colon' => null, | |
'edit_item' => __( 'Edit Tag' ), | |
'update_item' => __( 'Update Tag' ), | |
'add_new_item' => __( 'Add New Tag' ), | |
'new_item_name' => __( 'New Tag Name' ), | |
'separate_items_with_commas' => __( 'Separate tags with commas' ), | |
'add_or_remove_items' => __( 'Add or remove tags' ), | |
'choose_from_most_used' => __( 'Choose from the most used tags' ), | |
'menu_name' => __( 'Tags' ), | |
); | |
register_taxonomy('feattag','portfolio',array( | |
'hierarchical' => false, | |
'labels' => $labels, | |
'show_ui' => true, | |
'update_count_callback' => '_update_post_term_count', | |
'query_var' => true, | |
'rewrite' => array( 'slug' => 'feattag' ), | |
)); | |
/*============================ | |
======= END Taxonomy ====================================*/ | |
} | |
function my_rewrite_flush() { | |
flush_rewrite_rules(); | |
} | |
add_action( 'after_switch_theme', 'my_rewrite_flush' ); | |
/* fixes permalinks for custom post types */ | |
add_action('init', 'my_rewrite'); | |
function my_rewrite() { | |
global $wp_rewrite; | |
$wp_rewrite->add_permastruct('typename', 'typename/%year%/%postname%/', true, 1); | |
add_rewrite_rule('typename/([0-9]{4})/(.+)/?$', 'index.php?typename=$matches[2]', 'top'); | |
$wp_rewrite->flush_rules(); // !!! | |
} | |
/*======================= | |
SHOW THE EXCERPT | |
========================*/ | |
function my_custom_init() { | |
add_post_type_support( 'page', 'excerpt' ); | |
} | |
add_action('init', 'my_custom_init'); | |
/* ======================================================================== | |
=========== WOOCOMMERCE INTEGRATION WITH HOOKS AND FUNCTIONS =========== | |
=========================================================================*/ | |
remove_action( 'woocommerce_before_main_content', 'woocommerce_output_content_wrapper', 10); | |
remove_action( 'woocommerce_after_main_content', 'woocommerce_output_content_wrapper_end', 10); | |
/* hook in your own functions to display the wrappers your theme requires */ | |
add_action('woocommerce_before_main_content', 'my_theme_wrapper_start', 10); | |
add_action('woocommerce_after_main_content', 'my_theme_wrapper_end', 10); | |
function my_theme_wrapper_start() { | |
echo '<section id="main">'; | |
} | |
function my_theme_wrapper_end() { | |
echo '</section>'; | |
} | |
/* Make sure that the markup matches that of your theme. If you’re unsure of which classes or IDs to use, take a look at your theme’s page.php for a guide */ | |
/* Declare WooCommerce support */ | |
add_action( 'after_setup_theme', 'woocommerce_support' ); | |
function woocommerce_support() { | |
add_theme_support( 'woocommerce' ); | |
} | |
/*=============== END WOOCOMMERCE =================*/ | |
add_action('admin_head', 'my_custom_admin_style'); | |
function my_custom_admin_style() { | |
echo '<style> | |
.js .tmce-active .wp-editor-area { color: black !important; } | |
</style>'; | |
} | |
/*================================================ | |
=========META BOX FOR FULL WIDTH HEADER ========== | |
================================================*/ | |
/** | |
* Generated by the WordPress Meta Box generator | |
* at http://jeremyhixon.com/wp-tools/meta-box/ | |
*/ | |
function octane_theme_settings_get_meta( $value ) { | |
global $post; | |
$field = get_post_meta( $post->ID, $value, true ); | |
if ( ! empty( $field ) ) { | |
return is_array( $field ) ? stripslashes_deep( $field ) : stripslashes( wp_kses_decode_entities( $field ) ); | |
} else { | |
return false; | |
} | |
} | |
function octane_theme_settings_add_meta_box() { | |
add_meta_box( | |
'octane_theme_settings-octane-theme-settings', | |
__( 'Octane Theme Settings', 'octane_theme_settings' ), | |
'octane_theme_settings_octane_theme_settings_html', | |
'post', | |
'normal', | |
'high' | |
); | |
add_meta_box( | |
'octane_theme_settings-octane-theme-settings', | |
__( 'Octane Theme Settings', 'octane_theme_settings' ), | |
'octane_theme_settings_octane_theme_settings_html', | |
'page', | |
'normal', | |
'high' | |
); | |
add_meta_box( | |
'octane_theme_settings-octane-theme-settings', | |
__( 'Octane Theme Settings', 'octane_theme_settings' ), | |
'octane_theme_settings_octane_theme_settings_html', | |
'portfolio', | |
'normal', | |
'high' | |
); | |
add_meta_box( | |
'octane_theme_settings-octane-theme-settings', | |
__( 'Octane Theme Settings', 'octane_theme_settings' ), | |
'octane_theme_settings_octane_theme_settings_html', | |
'staff', | |
'normal', | |
'high' | |
); | |
add_meta_box( | |
'octane_theme_settings-octane-theme-settings', | |
__( 'Octane Theme Settings', 'octane_theme_settings' ), | |
'octane_theme_settings_octane_theme_settings_html', | |
'testimonial', | |
'normal', | |
'high' | |
); | |
} | |
add_action( 'add_meta_boxes', 'octane_theme_settings_add_meta_box' ); | |
function octane_theme_settings_octane_theme_settings_html( $post) { | |
wp_nonce_field( '_octane_theme_settings_octane_theme_settings_nonce', 'octane_theme_settings_octane_theme_settings_nonce' ); ?> | |
<p> | |
<p><strong>Full Header</strong></p> | |
<input type="checkbox" name="octane_theme_settings_octane_theme_settings_full_width_header_checkbox" id="octane_theme_settings_octane_theme_settings_full_width_header_checkbox" value="full-width-header-checkbox" <?php echo ( octane_theme_settings_get_meta( 'octane_theme_settings_octane_theme_settings_full_width_header_checkbox' ) === 'full-width-header-checkbox' ) ? 'checked' : ''; ?>> | |
<label for="octane_theme_settings_octane_theme_settings_full_width_header_checkbox"><?php _e( 'full_width_header_checkbox', 'octane_theme_settings' ); ?></label> </p> <p> | |
<?php | |
echo '<p><strong>Header Content</strong></p>'; | |
$settings = array( 'media_buttons' => false ); | |
$field_value = get_post_meta( $post->ID, 'OctaneHeaderContent', true ); | |
wp_editor( $field_value, 'OctaneHeaderContent', $settings); | |
?> | |
<?php | |
} | |
function octane_theme_settings_octane_theme_settings_save( $post_id ) { | |
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return $post_id; | |
if ( ! isset( $_POST['octane_theme_settings_octane_theme_settings_nonce'] ) || ! wp_verify_nonce( $_POST['octane_theme_settings_octane_theme_settings_nonce'], '_octane_theme_settings_octane_theme_settings_nonce' ) ) return; | |
if ( ! current_user_can( 'edit_post' ) ) return; | |
//full width header checkbox | |
if ( isset( $_POST['octane_theme_settings_octane_theme_settings_full_width_header_checkbox'] ) ) | |
update_post_meta( $post_id, 'octane_theme_settings_octane_theme_settings_full_width_header_checkbox', esc_attr( $_POST['octane_theme_settings_octane_theme_settings_full_width_header_checkbox'] ) ); | |
else | |
update_post_meta( $post_id, 'octane_theme_settings_octane_theme_settings_full_width_header_checkbox', null ); | |
if ( isset ( $_POST['OctaneHeaderContent'] ) ) { | |
update_post_meta( $post_id, 'OctaneHeaderContent', $_POST['OctaneHeaderContent'] ); | |
} | |
//big box checkbox for portfolios | |
/*if ( isset( $_POST['octane_theme_settings_octane_theme_settings_portfolio_big_box_checkbox'] ) && $post->post_type == 'portfolio' ) | |
update_post_meta( $post_id, 'octane_theme_settings_octane_theme_settings_portfolio_big_box_checkbox', esc_attr( $_POST['octane_theme_settings_octane_theme_settings_portfolio_big_box_checkbox'] ) ); | |
else | |
update_post_meta( $post_id, 'octane_theme_settings_octane_theme_settings_portfolio_big_box_checkbox', null ); */ | |
} | |
add_action( 'save_post', 'octane_theme_settings_octane_theme_settings_save' ); | |
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~~~Make Font Awesome available ~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | |
add_action( 'wp_enqueue_scripts', 'enqueue_font_awesome' ); | |
function enqueue_font_awesome() { | |
wp_enqueue_style( 'font-awesome', '//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css' ); | |
} | |
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~LOCATION EVENTS SHORTCODE ~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | |
function location_query_shortcode($atts) { | |
// EXAMPLE USAGE: | |
// [loop-location the_query="showposts=100&post_type=page&post_parent=453"] | |
// Defaults | |
extract(shortcode_atts(array( | |
"the_query" => '' | |
), $atts)); | |
// de-funkify query | |
$the_query = preg_replace('~�*([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $the_query); | |
$the_query = preg_replace('~�*([0-9]+);~e', 'chr(\\1)', $the_query); | |
// query is made | |
query_posts($the_query); | |
// Reset and setup variables | |
$output = ''; | |
$temp_title = ''; | |
$temp_link = ''; | |
$temp_date = ''; | |
// the loop | |
if (have_posts()) : while (have_posts()) : the_post(); | |
$temp_title = get_the_title($post->ID); | |
$temp_link = get_permalink($post->ID); | |
$temp_date = get_the_date($post->ID); | |
// output all findings - CUSTOMIZE TO YOUR LIKING | |
$output .= "<li>"; | |
$output .= "<a href='$temp_link'><h2>$temp_title</h2></a>"; | |
$output .= "<i>$temp_date</i>"; | |
$output .= "<br>"; | |
$output .= "<a class='read-more-link' href='$temp_link'>Read More</a>"; | |
$output .= "</li>"; | |
endwhile; else: | |
$output .= "nothing found."; | |
endif; | |
wp_reset_query(); | |
return $output; | |
} | |
add_shortcode("loop-location", "location_query_shortcode"); | |
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~~~LOCATION BLOG SHORTCODE ~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | |
function location_blog_query_shortcode($atts) { | |
// EXAMPLE USAGE: | |
// [loop-location the_query="showposts=100&post_type=page&post_parent=453"] | |
// Defaults | |
extract(shortcode_atts(array( | |
"the_query" => '' | |
), $atts)); | |
// de-funkify query | |
$the_query = preg_replace('~�*([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $the_query); | |
$the_query = preg_replace('~�*([0-9]+);~e', 'chr(\\1)', $the_query); | |
// query is made | |
query_posts($the_query); | |
// Reset and setup variables | |
$output = ''; | |
$temp_title = ''; | |
$temp_link = ''; | |
$temp_date = ''; | |
//$temp_pic = ''; | |
$temp_content = ''; | |
// the loop | |
if (have_posts()) : while (have_posts()) : the_post(); | |
$temp_title = get_the_title($post->ID); | |
$temp_link = get_permalink($post->ID); | |
$temp_date = get_the_date($post->ID); | |
$temp_pic = wp_get_attachment_url( get_post_thumbnail_id($post->ID) ); | |
$temp_content = wp_trim_words( get_the_content(), 10 ); | |
// output all findings - CUSTOMIZE TO YOUR LIKING | |
$output .= "<li class='clearfix'>"; | |
$output .= "<ul class='blog-container clearfix'>"; | |
$output .= "<li class='content-container clearfix'>"; | |
$output .= "<a href='$temp_link'><h2>$temp_title</h2></a>"; | |
$output .= "<i>$temp_date</i>"; | |
$output .= "<br>"; | |
$output .= "<p class='blog-content'>$temp_content</p>"; | |
$output .= "</li>"; | |
$output .= "<li class='img-container clearfix'>"; | |
if($temp_pic) { | |
$output .= "<a href='$temp_link'>"; | |
$output .= "<img class='blog-img-feat' src='$temp_pic'>"; | |
$output .= "</a>"; | |
} | |
$output .= "</li>"; | |
$output .= "</ul>"; | |
$output .= "<a class='read-more-link clearfix' href='$temp_link'>Read More</a>"; | |
$output .= "</li>"; | |
endwhile; else: | |
$output .= "nothing found."; | |
endif; | |
wp_reset_query(); | |
return $output; | |
} | |
add_shortcode("loop-blog", "location_blog_query_shortcode"); | |
/* =================== | |
ADMIN NOTICE | |
===================*/ | |
function wptutsplus_text_after_title( $post_type ) { | |
if ( $post_type = 'post' ) { | |
//echo "<pre>"; var_dump( $post_type ); echo "</pre><hr>"; | |
?> | |
<div class="after-title-help postbox"> | |
<h3>Warning for Keegan's blog posts...</h3> | |
<div class="inside"> | |
<p>Please make sure to include the location in the title of your blog posts.</p> | |
<p>Also, DO NOT categorize blog posts as both Blogs and Events.</p> | |
</div><!-- .inside --> | |
</div><!-- .postbox --> | |
<?php } //end if ?> | |
<?php } //end function | |
add_action( 'edit_form_after_title', 'wptutsplus_text_after_title' ); | |
add_action('admin_head', 'my_custom_admin_style'); | |
function my_custom_admin_style() { | |
echo '<style> | |
.after-title-help { margin: 20px 0 0 !important; border-radius: 10px; background: #ba030e !important; } | |
.after-title-help h3 { color: #f4c62e !important; } | |
.after-title-help p { color: #f4c62e; } | |
</style>'; | |
} | |
/* ======================================================================== | |
=================Enqueue Animate.CSS and WOW.js ============================== | |
========================================================================*/ | |
add_action( 'wp_enqueue_scripts', 'sk_enqueue_scripts' ); | |
function sk_enqueue_scripts() { | |
wp_enqueue_style( 'animate', get_stylesheet_directory_uri() . '/css/animate.min.css' ); | |
wp_enqueue_script( 'wow', get_stylesheet_directory_uri() . '/js/wow.min.js', array(), '', true ); | |
} | |
//* Enqueue script to activate WOW.js | |
add_action('wp_enqueue_scripts', 'sk_wow_init_in_footer'); | |
function sk_wow_init_in_footer() { | |
add_action( 'print_footer_scripts', 'wow_init' ); | |
} | |
//* Add JavaScript before </body> | |
function wow_init() { ?> | |
<script type="text/javascript"> | |
//new WOW().init(); | |
var wow = new WOW( | |
{ | |
boxClass: 'wow', // animated element css class (default is wow) | |
animateClass: 'animated', // animation css class (default is animated) | |
offset: 10, // distance to the element when triggering the animation (default is 0) | |
mobile: true, // trigger animations on mobile devices (true is default) | |
live: true | |
} | |
); | |
wow.init(); | |
</script> | |
<?php } | |
/* remove admin bar for all users when logged in */ | |
add_filter( 'show_admin_bar', '__return_false' ); | |
/* THIS REMOVES WPADMIN BAR FOR ANYONE OTHER THAN ADMIN OR EDITOR */ | |
if (!current_user_can('edit_posts')) { | |
add_filter('show_admin_bar', '__return_false'); | |
} | |
/* | |
* goes in theme functions.php or a custom plugin. Replace the image filename/path with your own :) | |
* | |
**/ | |
add_action( 'init', 'custom_fix_thumbnail' ); | |
function custom_fix_thumbnail() { | |
add_filter('woocommerce_placeholder_img_src', 'custom_woocommerce_placeholder_img_src'); | |
function custom_woocommerce_placeholder_img_src( $src ) { | |
$upload_dir = wp_upload_dir(); | |
$uploads = untrailingslashit( $upload_dir['baseurl'] ); | |
//$src = $uploads . '/2012/07/thumb1.jpg'; | |
$src = '//theloft.com/wp-content/themes/bootstrap-wp/images/woocommerce-ticket-default.png'; | |
return $src; | |
} | |
} | |
/* set the [ckhp-tribe-events] shortcode */ | |
function ckhp_get_tribe_events($atts) { | |
if ( !function_exists( 'tribe_get_events' ) ) { | |
return; | |
} | |
global $wp_query, $tribe_ecp, $post; | |
$output=''; | |
$ckhp_event_tax = ''; | |
extract( shortcode_atts( array( | |
'cat' => '', | |
'number' => 5, | |
'error' => 'y' | |
), $atts, 'ckhp-tribe-events' ), EXTR_PREFIX_ALL, 'ckhp' ); | |
if ( $ckhp_cat ) { | |
$ckhp_event_tax = array( | |
array( | |
'taxonomy' => 'tribe_events_cat', | |
'field' => 'slug', | |
'terms' => $ckhp_cat | |
) | |
); | |
} | |
$posts = tribe_get_events(apply_filters('tribe_events_list_widget_query_args', array( | |
'eventDisplay' => 'upcoming', | |
'posts_per_page' => $ckhp_number, | |
'tax_query'=> $ckhp_event_tax | |
))); | |
if ( $posts && !$no_upcoming_events) { | |
$output .= '<ul class="hfeed vcalendar ckhp-small ckhp-event-list">'; | |
foreach( $posts as $post ) : | |
setup_postdata( $post ); | |
$output .= '<li class="">'; | |
$output .= '<h4 class="entry-title summary">' . '<a href="' . tribe_get_event_link() . '" rel="bookmark">' . get_the_title() . '</a>' . '</h4>'; | |
$output .= '<div class="duration venue">' . tribe_events_event_schedule_details() . ' ' . tribe_get_venue() . '</div>'; | |
$output .= '</li>'; | |
endforeach; | |
$output .= '</ul><!-- .hfeed -->'; | |
$output .= '<p class="tribe-events-widget-link"><a href="' . tribe_get_events_link() . '" rel="bookmark">' . translate( 'View All Events', 'tribe-events-calendar' ) . '</a></p>'; | |
} else { //No Events were Found | |
$output .= ( $ckhp_error == 'y' ? '<p>' . translate( 'There are no upcoming events at this time.', 'tribe-events-calendar' ) . '</p>' : '' ) ; | |
} // endif | |
wp_reset_query(); | |
return $output; | |
} | |
add_shortcode('ckhp-tribe-events', 'ckhp_get_tribe_events'); // link new function to shortcode name | |
/* THIS REMOVES WPADMIN BAR FOR ANYONE OTHER THAN ADMIN OR EDITOR */ | |
if (!current_user_can('edit_posts')) { | |
add_filter('show_admin_bar', '__return_false'); | |
} | |
/* ===================================================== | |
this function cleans up the admin menu for everyone other than wpadmin | |
======================================================*/ | |
add_action('admin_init', 'wpse74389_check_username'); | |
function wpse74389_check_username() | |
{ | |
$user = wp_get_current_user(); | |
if($user && isset($user->user_login) && 'wpadmin' != $user->user_login) | |
{ | |
//remove_menu_page('index.php'); // Dashboard tab | |
//remove_menu_page('edit.php'); // Posts | |
//remove_menu_page('edit.php?post_type=page'); // Pages | |
//remove_menu_page('upload.php'); // Media | |
//remove_menu_page('link-manager.php'); // Links | |
remove_menu_page('edit-comments.php'); // Comments | |
remove_menu_page('themes.php'); // Appearance | |
remove_menu_page('plugins.php'); // Plugins | |
//remove_menu_page('users.php'); // Users | |
remove_menu_page('tools.php'); // Tools | |
//remove_menu_page('options-general.php'); // Settings | |
remove_menu_page('et_bloom_options'); //bloom | |
remove_menu_page('rich_snippet_dashboard'); //rich snippets | |
remove_menu_page('wordpress-https'); //https | |
remove_menu_page('edit.php?post_type=csp-report'); //mix content report | |
remove_menu_page('edit.php?post_type=portfolio'); //portfolios | |
remove_menu_page('layerslider'); //layerslider | |
remove_menu_page('oa_social_login_setup'); //social login | |
remove_menu_page('feed-them-settings-page'); //feem them social | |
remove_menu_page('bws_plugins'); //google sitemap | |
remove_menu_page('w3tc_dashboard'); //W3 Total cache | |
} | |
} | |
/*~~~~~~~~~~~~~~~~ | |
~~~~~~PHOTOS~~~~~~ | |
~~~~~~~~~~~~~~~~*/ | |
/*If you don't see featured images on your theme USE THIS */ | |
add_theme_support('post-thumbnails'); | |
/* Create a custom feated image size */ | |
add_image_size('custom-name', 55, 55, true); | |
/*~~~~~~~~~~~~~~~~ | |
~~~~~~PHOTOS~~~~~~ | |
~~~~~~~~~~~~~~~~*/ | |
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | |
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~~~~create custom column | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | |
add_image_size('featured_preview', 55, 55, true); | |
/*Now we'll add a new column in the Posts list table that will contain the featured image of each Post. | |
But first, we need a function to get the featured image of a Post: */ | |
// GET FEATURED IMAGE | |
function ST4_get_featured_image($post_ID) { | |
$post_thumbnail_id = get_post_thumbnail_id($post_ID); | |
if ($post_thumbnail_id) { | |
$post_thumbnail_img = wp_get_attachment_image_src($post_thumbnail_id, 'featured_preview'); | |
return $post_thumbnail_img[0]; | |
} | |
} | |
/* And we define two functions: the first will add the new column, | |
the second will call and show the featured image in every cell of the new column: */ | |
// ADD NEW COLUMN | |
function ST4_columns_head($defaults) { | |
$defaults['featured_image'] = 'Featured Image'; | |
return $defaults; | |
} | |
// SHOW THE FEATURED IMAGE | |
function ST4_columns_content($column_name, $post_ID) { | |
if ($column_name == 'featured_image') { | |
$post_featured_image = ST4_get_featured_image($post_ID); | |
if ($post_featured_image) { | |
echo '<img src="' . $post_featured_image . '" />'; | |
} | |
} | |
} | |
/* | |
In short, Hooks allow developers to extend WordPress features without editing core files. There are two types of Hooks: Actions and Filters. | |
Both are launched during WordPress execution, but while Filters accept, transform and return an input, Actions return nothing, though can print everything you need. | |
In our case, the ST4_columns_head function takes the $defaults array that contains the default Posts table columns (Title, Category, Tags and so on...), | |
adds a new featured_image item to the array and returns it to the core function that WordPress uses to print the table html. | |
On the contrary, the ST4_columns_content function accepts two variables ($column_name and $post_ID), and – depending on them – prints an output. | |
To be more precise, ST4_columns_content is invoked on each iteration of the loop that traverses the $defaults array. | |
On each iteration, WordPress passes two arguments to our function: the column name and the post ID. The function analyzes all column names and when | |
the name is equal to the one we specified in ST4_columns_head, checks for featured image. | |
*/ | |
add_filter('manage_posts_columns', 'ST4_columns_head'); | |
add_action('manage_posts_custom_column', 'ST4_columns_content', 10, 2); | |
/* Add the Featured Image Column to Custom Post Types */ | |
add_action('init', 'ST4_add_movies'); | |
function ST4_add_movies() { | |
$args = array( | |
'label' => __('Movies'), | |
'singular_label' => __('Movie'), | |
'public' => true, | |
'show_ui' => true, | |
'capability_type' => 'post', | |
'hierarchical' => false, | |
'rewrite' => true, | |
'supports' => array('title', 'editor', 'thumbnail') | |
); | |
register_post_type( 'movie' , $args ); | |
} | |
/* | |
Adding the Custom Column Depending on Post Type | |
If you use the manage_posts_columns and manage_posts_custom_column | |
hooks, the column will be shown in all manage posts screens. These filters in fact | |
will work for posts of all types except Pages. | |
*/ | |
// ALL POST TYPES: posts AND custom post types | |
add_filter('manage_posts_columns', 'ST4_columns_head'); | |
add_action('manage_posts_custom_column', 'ST4_columns_content', 10, 2); | |
/* If you want to add a column only in the manage Posts screen use: */ | |
// ONLY WORDPRESS DEFAULT POSTS | |
add_filter('manage_post_posts_columns', 'ST4_columns_head', 10); | |
add_action('manage_post_posts_custom_column', 'ST4_columns_content', 10, 2); | |
/* | |
If you want to add a column only in the manage Pages screen use: | |
*/ | |
// ONLY WORDPRESS DEFAULT PAGES | |
add_filter('manage_page_posts_columns', 'ST4_columns_head', 10); | |
add_action('manage_page_posts_custom_column', 'ST4_columns_content', 10, 2); | |
/* If you want to add a column only in the manage Movies screen use: */ | |
// ONLY MOVIE CUSTOM TYPE POSTS | |
add_filter('manage_movie_posts_columns', 'ST4_columns_head_only_movies', 10); | |
add_action('manage_movie_posts_custom_column', 'ST4_columns_content_only_movies', 10, 2); | |
// CREATE TWO FUNCTIONS TO HANDLE THE COLUMN | |
function ST4_columns_head_only_movies($defaults) { | |
$defaults['directors_name'] = 'Director'; | |
return $defaults; | |
} | |
function ST4_columns_content_only_movies($column_name, $post_ID) { | |
if ($column_name == 'directors_name') { | |
// show content of 'directors_name' column | |
} | |
} | |
// ADD TWO NEW COLUMNS | |
function ST4_columns_head($defaults) { | |
$defaults['first_column'] = 'First Column'; | |
$defaults['second_column'] = 'Second Column'; | |
return $defaults; | |
} | |
function ST4_columns_content($column_name, $post_ID) { | |
if ($column_name == 'first_column') { | |
// First column | |
} | |
if ($column_name == 'second_column') { | |
// Second column | |
} | |
} | |
//REMOVE DEFAULT COLUMNS | |
add_filter('manage_post_posts_columns', 'ST4_columns_remove_category'); | |
// REMOVE DEFAULT CATEGORY COLUMN | |
function ST4_columns_remove_category($defaults) { | |
// to get defaults column names: | |
// print_r($defaults); | |
unset($defaults['categories']); | |
return $defaults; | |
} | |
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | |
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
CREATING CUSTOM POST TYPES EXAMPLE STRAIGHT FROM WORDPRESS (DETAILED VERSION) | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | |
add_action( 'init', 'codex_book_init' ); | |
/** | |
* Register a book post type. | |
* This is an example to show all the options for label and supports | |
* @link http://codex.wordpress.org/Function_Reference/register_post_type | |
*/ | |
function codex_book_init() { | |
$labels = array( | |
'name' => _x( 'Books', 'post type general name', 'your-plugin-textdomain' ), | |
'singular_name' => _x( 'Book', 'post type singular name', 'your-plugin-textdomain' ), | |
'menu_name' => _x( 'Books', 'admin menu', 'your-plugin-textdomain' ), | |
'name_admin_bar' => _x( 'Book', 'add new on admin bar', 'your-plugin-textdomain' ), | |
'add_new' => _x( 'Add New', 'book', 'your-plugin-textdomain' ), | |
'add_new_item' => __( 'Add New Book', 'your-plugin-textdomain' ), | |
'new_item' => __( 'New Book', 'your-plugin-textdomain' ), | |
'edit_item' => __( 'Edit Book', 'your-plugin-textdomain' ), | |
'view_item' => __( 'View Book', 'your-plugin-textdomain' ), | |
'all_items' => __( 'All Books', 'your-plugin-textdomain' ), | |
'search_items' => __( 'Search Books', 'your-plugin-textdomain' ), | |
'parent_item_colon' => __( 'Parent Books:', 'your-plugin-textdomain' ), | |
'not_found' => __( 'No books found.', 'your-plugin-textdomain' ), | |
'not_found_in_trash' => __( 'No books found in Trash.', 'your-plugin-textdomain' ) | |
); | |
$args = array( | |
'labels' => $labels, | |
'public' => true, | |
'publicly_queryable' => true, | |
'show_ui' => true, | |
'show_in_menu' => true, | |
'query_var' => true, | |
'rewrite' => array( 'slug' => 'book' ), | |
'capability_type' => 'post', | |
'has_archive' => true, | |
'hierarchical' => false, | |
'menu_position' => null, | |
'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' ) | |
); | |
register_post_type( 'book', $args ); | |
} | |
/* customize the messages */ | |
add_filter( 'post_updated_messages', 'codex_book_updated_messages' ); | |
/** | |
* Book update messages. | |
* | |
* See /wp-admin/edit-form-advanced.php | |
* | |
* @param array $messages Existing post update messages. | |
* | |
* @return array Amended post update messages with new CPT update messages. | |
*/ | |
function codex_book_updated_messages( $messages ) { | |
$post = get_post(); | |
$post_type = get_post_type( $post ); | |
$post_type_object = get_post_type_object( $post_type ); | |
$messages['book'] = array( | |
0 => '', // Unused. Messages start at index 1. | |
1 => __( 'Book updated.', 'your-plugin-textdomain' ), | |
2 => __( 'Custom field updated.', 'your-plugin-textdomain' ), | |
3 => __( 'Custom field deleted.', 'your-plugin-textdomain' ), | |
4 => __( 'Book updated.', 'your-plugin-textdomain' ), | |
/* translators: %s: date and time of the revision */ | |
5 => isset( $_GET['revision'] ) ? sprintf( __( 'Book restored to revision from %s', 'your-plugin-textdomain' ), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, | |
6 => __( 'Book published.', 'your-plugin-textdomain' ), | |
7 => __( 'Book saved.', 'your-plugin-textdomain' ), | |
8 => __( 'Book submitted.', 'your-plugin-textdomain' ), | |
9 => sprintf( | |
__( 'Book scheduled for: <strong>%1$s</strong>.', 'your-plugin-textdomain' ), | |
// translators: Publish box date format, see http://php.net/date | |
date_i18n( __( 'M j, Y @ G:i', 'your-plugin-textdomain' ), strtotime( $post->post_date ) ) | |
), | |
10 => __( 'Book draft updated.', 'your-plugin-textdomain' ) | |
); | |
if ( $post_type_object->publicly_queryable ) { | |
$permalink = get_permalink( $post->ID ); | |
$view_link = sprintf( ' <a href="%s">%s</a>', esc_url( $permalink ), __( 'View book', 'your-plugin-textdomain' ) ); | |
$messages[ $post_type ][1] .= $view_link; | |
$messages[ $post_type ][6] .= $view_link; | |
$messages[ $post_type ][9] .= $view_link; | |
$preview_permalink = add_query_arg( 'preview', 'true', $permalink ); | |
$preview_link = sprintf( ' <a target="_blank" href="%s">%s</a>', esc_url( $preview_permalink ), __( 'Preview book', 'your-plugin-textdomain' ) ); | |
$messages[ $post_type ][8] .= $preview_link; | |
$messages[ $post_type ][10] .= $preview_link; | |
} | |
return $messages; | |
} //end of customize messages | |
/* display contextual help */ | |
//display contextual help for Books | |
function codex_add_help_text( $contextual_help, $screen_id, $screen ) { | |
//$contextual_help .= var_dump( $screen ); // use this to help determine $screen->id | |
if ( 'book' == $screen->id ) { | |
$contextual_help = | |
'<p>' . __('Things to remember when adding or editing a book:', 'your_text_domain') . '</p>' . | |
'<ul>' . | |
'<li>' . __('Specify the correct genre such as Mystery, or Historic.', 'your_text_domain') . '</li>' . | |
'<li>' . __('Specify the correct writer of the book. Remember that the Author module refers to you, the author of this book review.', 'your_text_domain') . '</li>' . | |
'</ul>' . | |
'<p>' . __('If you want to schedule the book review to be published in the future:', 'your_text_domain') . '</p>' . | |
'<ul>' . | |
'<li>' . __('Under the Publish module, click on the Edit link next to Publish.', 'your_text_domain') . '</li>' . | |
'<li>' . __('Change the date to the date to actual publish this article, then click on Ok.', 'your_text_domain') . '</li>' . | |
'</ul>' . | |
'<p><strong>' . __('For more information:', 'your_text_domain') . '</strong></p>' . | |
'<p>' . __('<a href="http://codex.wordpress.org/Posts_Edit_SubPanel" target="_blank">Edit Posts Documentation</a>', 'your_text_domain') . '</p>' . | |
'<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>', 'your_text_domain') . '</p>' ; | |
} elseif ( 'edit-book' == $screen->id ) { | |
$contextual_help = | |
'<p>' . __('This is the help screen displaying the table of books blah blah blah.', 'your_text_domain') . '</p>' ; | |
} | |
return $contextual_help; | |
} | |
add_action( 'contextual_help', 'codex_add_help_text', 10, 3 ); | |
//end contextual help | |
/* custom help tab */ | |
function codex_custom_help_tab() { | |
$screen = get_current_screen(); | |
// Return early if we're not on the book post type. | |
if ( 'book' != $screen->post_type ) | |
return; | |
// Setup help tab args. | |
$args = array( | |
'id' => 'you_custom_id', //unique id for the tab | |
'title' => 'Custom Help', //unique visible title for the tab | |
'content' => '<h3>Help Title</h3><p>Help content</p>', //actual help text | |
); | |
// Add the help tab. | |
$screen->add_help_tab( $args ); | |
} | |
add_action('admin_head', 'codex_custom_help_tab'); | |
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
* Flushing Rewrite on Activation - | |
* To get permalinks to work when you activate the plugin use the following example, | |
paying attention to how my_cpt_init is called in the register_activation_hook callback | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | |
add_action( 'init', 'my_cpt_init' ); | |
function my_cpt_init() { | |
register_post_type( ... ); | |
} | |
function my_rewrite_flush() { | |
// First, we "add" the custom post type via the above written function. | |
// Note: "add" is written with quotes, as CPTs don't get added to the DB, | |
// They are only referenced in the post_type column with a post entry, | |
// when you add a post of this CPT. | |
my_cpt_init(); | |
// ATTENTION: This is *only* done during plugin activation hook in this example! | |
// You should *NEVER EVER* do this on every page load!! | |
flush_rewrite_rules(); | |
} | |
register_activation_hook( __FILE__, 'my_rewrite_flush' ); | |
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
* For themes, you'll need to use the after_switch_theme hook instead. Like so - | |
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | |
add_action( 'init', 'my_cpt_init' ); | |
function my_cpt_init() { | |
register_post_type( ... ); | |
} | |
function my_rewrite_flush() { | |
flush_rewrite_rules(); | |
} | |
add_action( 'after_switch_theme', 'my_rewrite_flush' ); | |
/* =================== | |
ADMIN NOTICE | |
===================*/ | |
function wptutsplus_text_after_title( $post_type ) { | |
if ( $post_type = 'post' ) { | |
//echo "<pre>"; var_dump( $post_type ); echo "</pre><hr>"; | |
?> | |
<div class="after-title-help postbox"> | |
<h3>Warning for Keegan's blog posts...</h3> | |
<div class="inside"> | |
<p>Please make sure to include the location in the title of your blog posts.</p> | |
<p>Also, DO NOT categorize blog posts as both Blogs and Events.</p> | |
</div><!-- .inside --> | |
</div><!-- .postbox --> | |
<?php } //end if ?> | |
<?php } //end function | |
add_action( 'edit_form_after_title', 'wptutsplus_text_after_title' ); | |
add_action('admin_head', 'my_custom_admin_style'); | |
function my_custom_admin_style() { | |
echo '<style> | |
.after-title-help { margin: 20px 0 0 !important; border-radius: 10px; background: #ba030e !important; } | |
.after-title-help h3 { color: #f4c62e !important; } | |
.after-title-help p { color: #f4c62e; } | |
</style>'; | |
} | |
/** | |
* Redirects users away from login page if they're already logged in | |
* or Redirects to /store/ if they log out. | |
* | |
* @since 0.4.0 | |
* | |
* @return void | |
*/ | |
function login_out_page_redirect() { | |
if ( is_user_logged_in() && 'login' == $this->_current_view ) { | |
wp_redirect( it_exchange_get_page_url( 'account' ) ); | |
die(); | |
} else if ( is_user_logged_in() && 'logout' == $this->_current_view ) { | |
$default = 'disabled' == it_exchange_get_page_type( 'login' ) ? get_home_url() : str_replace( '&', '&', wp_logout_url( it_exchange_get_page_url( 'login', false, true ) ) ); | |
$url = apply_filters( 'it_exchange_redirect_on_logout', $default ); | |
wp_redirect( $url ); | |
die(); | |
} else if ( ! is_user_logged_in() && 'logout' == $this->_current_view ) { | |
wp_redirect( it_exchange_get_page_url( 'login' ) ); | |
die(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment