' . esc_html( get_the_title( $p ) ) . '
' . esc_html( wp_trim_words( wp_strip_all_tags( $p->post_content ), 30 ) ) . '
boot(); ( new Messages() )->boot(); add_action( 'init', array( $this, 'register_cpts' ) ); add_filter( 'frontglut_menu_items', array( $this, 'menu' ) ); add_filter( 'frontglut_widgets', array( $this, 'widgets' ) ); add_filter( 'frontglut_topbar_html', array( $this, 'bell' ) ); add_filter( 'frontglut_managed_post_types', function ( $t ) { $t[] = 'frontglut_kb'; return $t; } ); add_filter( 'frontglut_can_submit', function ( $ok, $pt ) { return 'frontglut_kb' === $pt ? Caps::can( 'frontglut_moderate' ) : $ok; }, 10, 2 ); add_filter( 'frontglut_can_edit_post', function ( $ok, $post ) { return 'frontglut_kb' === $post->post_type ? Caps::can( 'frontglut_moderate' ) : $ok; }, 10, 2 ); add_filter( 'frontglut_post_status', function ( $s, $f, $uid, $pt ) { return 'frontglut_kb' === $pt ? 'publish' : $s; }, 10, 4 ); add_filter( 'frontglut_section_for_post_type', function ( $s, $pt ) { return 'frontglut_kb' === $pt ? 'kb' : $s; }, 10, 2 ); add_shortcode( 'frontglut_kb', array( $this, 'sc_kb' ) ); add_shortcode( 'frontglut_follow', array( $this, 'sc_follow' ) ); add_action( 'frontglut_daily', array( $this, 'digest' ) ); foreach ( array( 'notif_read', 'notif_delete', 'notice_send', 'notice_delete', 'follow_toggle' ) as $a ) { Ajax::register( $a, array( $this, 'ajax_' . $a ), array( 'cap' => 'notice_send' === $a || 'notice_delete' === $a ? 'frontglut_send_notices' : null ) ); } add_action( 'woocommerce_after_single_product_summary', function () { global $product; if ( $product && class_exists( '\FrontGlut\Modules\Vendors\Vendors' ) && ( $v = \FrontGlut\Modules\Vendors\Vendors::product_vendor( $product->get_id() ) ) ) { echo wp_kses( do_shortcode( '[frontglut_follow id="' . (int) $v . '" type="store"]' ), Ui::allowed_html() ); } }, 5 ); add_filter( 'the_content', function ( $c ) { if ( is_singular( 'post' ) && in_the_loop() && is_main_query() && get_post_meta( get_the_ID(), '_frontglut_form', true ) ) { $c .= do_shortcode( '[frontglut_follow id="' . (int) get_post_field( 'post_author', get_the_ID() ) . '" type="author"]' ); } return $c; } ); } public function register_cpts() { register_post_type( 'frontglut_kb', array( 'labels' => array( 'name' => __( 'Knowledge base', 'frontglut' ), 'singular_name' => __( 'Article', 'frontglut' ) ), 'public' => true, 'has_archive' => false, 'show_in_rest' => true, 'supports' => array( 'title', 'editor', 'thumbnail' ), 'rewrite' => array( 'slug' => 'help' ), 'show_in_menu' => 'frontglut', 'taxonomies' => array( 'frontglut_kb_cat' ) ) ); register_taxonomy( 'frontglut_kb_cat', 'frontglut_kb', array( 'labels' => array( 'name' => __( 'KB categories', 'frontglut' ) ), 'hierarchical' => true, 'public' => true, 'show_in_rest' => true, 'rewrite' => array( 'slug' => 'help-topic' ) ) ); register_post_type( 'frontglut_notice', array( 'labels' => array( 'name' => 'Announcements' ), 'public' => false, 'supports' => array( 'title', 'editor' ) ) ); if ( ! get_option( 'frontglut_kb_form' ) || ! Forms::get( (int) get_option( 'frontglut_kb_form' ) ) ) { $id = Forms::save( array( 'type' => 'post', 'title' => 'Knowledge base article', 'settings' => Forms::post_settings( array( 'post_type' => 'frontglut_kb', 'status' => 'publish', 'editor' => 'lite', 'notify_admin' => 0, 'notify_user' => 0 ) ), 'fields' => array( Forms::f( 'title', 'text', __( 'Title', 'frontglut' ), array( 'required' => 1, 'storage' => 'post_title' ) ), Forms::f( 'content', 'editor', __( 'Answer', 'frontglut' ), array( 'required' => 1, 'storage' => 'post_content' ) ), Forms::f( 'topic', 'taxonomy', __( 'Topic', 'frontglut' ), array( 'storage' => 'tax', 'taxonomy' => 'frontglut_kb_cat', 'ui' => 'checkboxes' ) ), ) ) ); update_option( 'frontglut_kb_form', $id, false ); } } public function menu( $i ) { $i['notifications'] = array( 'label' => __( 'Notifications', 'frontglut' ), 'icon' => 'bell', 'group' => 'comms', 'order' => 60, 'render' => array( $this, 'screen_notifications' ), 'badge' => array( 'FrontGlut\\Core\\Notify', 'unread' ) ); $i['notices'] = array( 'label' => __( 'Announcements', 'frontglut' ), 'icon' => 'megaphone', 'group' => 'comms', 'order' => 64, 'cap' => 'frontglut_send_notices', 'render' => array( $this, 'screen_notices' ) ); $i['kb'] = array( 'label' => __( 'Knowledge base', 'frontglut' ), 'icon' => 'book', 'group' => 'comms', 'order' => 65, 'cap' => 'frontglut_moderate', 'render' => function () { $posts = \FrontGlut\Core\Plugin::instance()->modules()->get( 'posts' ); return $posts ? $posts->manage_screen( 'kb', 'frontglut_kb', __( 'Knowledge base', 'frontglut' ), (int) get_option( 'frontglut_kb_form' ) ) : ''; } ); return $i; } public function widgets( $w ) { $w['announcements'] = array( 'title' => __( 'Announcements', 'frontglut' ), 'order' => 3, 'size' => 2, 'render' => array( $this, 'widget_notices' ) ); $w['recent_notifs'] = array( 'title' => __( 'Recent notifications', 'frontglut' ), 'order' => 45, 'size' => 1, 'render' => function () { $n = Notify::latest( get_current_user_id(), 5 ); if ( ! $n ) { return '
' . esc_html__( 'You are all caught up.', 'frontglut' ) . '
'; } $h = '' . Ui::btn( __( 'All notifications', 'frontglut' ), Dashboard::url( 'notifications' ), 'frontglut-sm' ) . '
'; } ); return $w; } public function bell( $h ) { $n = Notify::unread(); return $h . '' . Ui::icon( 'bell' ) . ( $n ? '' . (int) min( 99, $n ) . '' : '' ) . ''; } /* ---------------- notifications ---------------- */ public function screen_notifications() { $uid = get_current_user_id(); $pg = Request::page(); $list = Notify::latest( $uid, 20, ( $pg - 1 ) * 20 ); global $wpdb; $tot = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}frontglut_notifications WHERE user_id = %d", $uid ) ); // phpcs:ignore WordPress.DB.PreparedSQL $rows = array(); foreach ( $list as $n ) { $rows[] = array( 'msg' => ( $n['is_read'] ? '' : '' ) . ( $n['url'] ? '' . esc_html( $n['title'] ) . '' : esc_html( $n['title'] ) ) . ( $n['is_read'] ? '' : '' ) . ( $n['message'] ? '' . esc_html( sprintf( _n( '%d follower', '%d followers', $cnt, 'frontglut' ), $cnt ) ) . '
'; } public function ajax_follow_toggle( $req ) { global $wpdb; $id = (int) ( $req['id'] ?? 0 ); $type = 'store' === ( $req['type'] ?? '' ) ? 'store' : 'author'; $uid = get_current_user_id(); if ( ! $id || $id === $uid || ! get_userdata( $id ) ) { Ajax::fail( __( 'Invalid request.', 'frontglut' ) ); } $t = $wpdb->prefix . 'frontglut_follows'; if ( $wpdb->get_var( $wpdb->prepare( "SELECT id FROM $t WHERE user_id = %d AND target_id = %d AND type = %s", $uid, $id, $type ) ) ) { // phpcs:ignore WordPress.DB.PreparedSQL $wpdb->delete( $t, array( 'user_id' => $uid, 'target_id' => $id, 'type' => $type ) ); return array( 'message' => __( 'Unfollowed.', 'frontglut' ) ); } $wpdb->insert( $t, array( 'user_id' => $uid, 'target_id' => $id, 'type' => $type, 'created' => current_time( 'mysql', true ) ) ); /* translators: %s: value. */ Notify::send( $id, sprintf( __( '%s followed you', 'frontglut' ), wp_get_current_user()->display_name ), '', Dashboard::url() ); return array( 'message' => __( 'Following!', 'frontglut' ) ); } /** Daily digest of new products/posts from followed stores/authors. */ public function digest() { global $wpdb; $since = gmdate( 'Y-m-d H:i:s', time() - DAY_IN_SECONDS ); $rows = $wpdb->get_results( "SELECT user_id, target_id, type FROM {$wpdb->prefix}frontglut_follows", ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL $by = array(); foreach ( $rows as $r ) { $by[ $r['user_id'] ][] = $r; } foreach ( $by as $uid => $follows ) { $lines = array(); foreach ( $follows as $f ) { $posts = get_posts( array( 'author' => $f['target_id'], 'post_type' => 'store' === $f['type'] ? 'product' : 'post', 'post_status' => 'publish', 'date_query' => array( array( 'after' => $since, 'column' => 'post_date_gmt' ) ), 'numberposts' => 5 ) ); foreach ( $posts as $p ) { $lines[] = '• ' . get_the_title( $p ) . ' — ' . get_permalink( $p ); } } $u = get_userdata( $uid ); if ( $lines && $u ) { /* translators: %s: value. */ Mailer::send( $u->user_email, sprintf( __( 'New from the stores and authors you follow — %s', 'frontglut' ), get_bloginfo( 'name' ) ), implode( "\n", $lines ) ); } } } /* ---------------- knowledge base ---------------- */ public function sc_kb( $atts ) { Assets::need(); $q = Request::route( 'kq', 'text', '' ); $cat = Request::route( 'kc', 'int', 0 ); $args = array( 'post_type' => 'frontglut_kb', 'post_status' => 'publish', 'posts_per_page' => 30, 's' => $q ); if ( $cat ) { $args['tax_query'] = array( array( 'taxonomy' => 'frontglut_kb_cat', 'terms' => array( $cat ) ) ); } $h = '' . esc_html( wp_trim_words( wp_strip_all_tags( $p->post_content ), 30 ) ) . '
' . esc_html__( 'No articles found.', 'frontglut' ) . '
' ) . '