UserModel, 'item_id' => int|string ] * * @throws Exception */ public function layout( array $data = [] ) { try { $userModel = $data['userModel'] ?? false; if ( ! $userModel || ! $userModel->is_instructor() ) { throw new Exception( __( 'You do not have permission to create or edit questions', 'learnpress' ) ); } $item_id = $data['item_id'] ?? ''; if ( empty( $item_id ) ) { throw new Exception( __( 'Invalid question ID', 'learnpress' ) ); } /*if ( ! CourseBuilderAccessPolicy::can_access_tab_post( 'questions', $item_id ) ) { throw new Exception( __( "Sorry, you don't have permission to access this content", 'learnpress' ) ); }*/ $is_create_new = $item_id === CourseBuilder::POST_NEW; $questionModel = false; if ( ! $is_create_new ) { $questionModel = QuestionPostModel::find( (int) $item_id, true ); if ( ! $questionModel ) { throw new Exception( __( 'Question not found', 'learnpress' ) ); } $questionModel->check_capabilities_update_item_course(); if ( $questionModel->post_status === PostModel::STATUS_TRASH ) { throw new Exception( __( 'You cannot edit this item because it is in the Trash. Please restore it and try again.', 'learnpress' ) ); } } else { $questionModelNew = new QuestionPostModel(); $questionModelNew->check_capabilities_create_item_course(); } $data['questionModel'] = $questionModel; $section = [ 'wrap' => sprintf( '
', esc_attr( $item_id ) ), 'header' => $this->html_header( $data ), 'tabs' => $this->html_tabs( $data ), 'wrap_end' => '
', ]; echo Template::combine_components( $section ); } catch ( Throwable $e ) { Template::print_message( $e->getMessage(), 'error' ); } } public function html_header( array $data = [] ): string { $userModel = $data['userModel'] ?? false; if ( ! $userModel instanceof UserModel ) { return ''; } $questionModel = $data['questionModel'] ?? false; $hide_instructor_access_admin_screen = LP_Settings::is_hide_instructor_access_admin_screen(); $more_actions_icon = LP_WP_Filesystem::get_icon_svg( 'ico-cb-more.svg' ); $title = $questionModel ? $questionModel->get_the_title() : __( 'Add New Question', 'learnpress' ); $status = $questionModel ? $questionModel->post_status : ''; $status_label = 'future' === $status ? __( 'scheduled', 'learnpress' ) : $status; $main_action_status = in_array( $status, [ 'publish', 'draft', 'pending', 'future', 'private' ], true ) ? $status : 'publish'; $wp_user = new WP_User( $userModel ); $hide_wp_edit_link = $hide_instructor_access_admin_screen && user_can( $wp_user, UserModel::ROLE_INSTRUCTOR ); $section = [ 'header_wrap' => '
', 'header_left' => '
', 'title' => sprintf( '

%s

', esc_html( $title ) ), 'status_badge' => $questionModel && $status ? sprintf( '%2$s', esc_attr( $status ), esc_html( $status_label ) ) : '', 'link_edit_on_wp' => $questionModel && ! $hide_wp_edit_link ? sprintf( ' %2$s ', esc_url( admin_url( 'post.php?post=' . $questionModel->get_id() . '&action=edit' ) ), esc_attr__( 'Edit with WordPress', 'learnpress' ), 'trash' === $status ? ' style="display:none"' : '' ) : '', 'header_left_end' => '
', 'header_actions' => '
', 'dropdown_wrap' => '
', 'update_btn' => sprintf( '
%5$s
', esc_attr( $main_action_status ), esc_attr__( 'Update', 'learnpress' ), esc_attr__( 'Publish', 'learnpress' ), esc_attr__( 'Save Draft', 'learnpress' ), esc_html__( 'Update', 'learnpress' ) ), 'dropdown_wrap_end' => '
', 'expanded_actions' => $questionModel ? sprintf( '
%5$s
%6$s
', esc_attr__( 'More actions', 'learnpress' ), $more_actions_icon, esc_attr__( 'Are you sure?', 'learnpress' ), esc_attr__( 'Are you sure you want to duplicate this question?', 'learnpress' ), esc_html__( 'Duplicate', 'learnpress' ), esc_html__( 'Move to Trash', 'learnpress' ) ) : '', 'header_actions_end' => '
', 'header_end' => '
', ]; return Template::combine_components( $section ); } public function html_tabs( array $data = [] ): string { $section_tab = [ 'tabs_wrap' => '
', 'tabs' => '', 'tabs_end' => '
', ]; $section_content = [ 'wrap' => '
', 'content' => '', 'wrap-end' => '
', ]; $tabs = apply_filters( 'learn-press/course-builder/questions/edit/tabs', [ 'overview' => [ 'title' => esc_html__( 'Overview', 'learnpress' ), 'html' => $this->html_tab_overview( $data ), ], 'settings' => [ 'title' => esc_html__( 'Settings', 'learnpress' ), 'html' => $this->html_tab_settings( $data ), ], ], $data ); $tab_sections = []; foreach ( $tabs as $key => $tab ) { $tab_sections[ $key ] = $tab['slug'] ?? $key; } $tab_active = (string) reset( $tab_sections ); if ( isset( $_GET['tab'] ) ) { $requested_tab = sanitize_key( wp_unslash( $_GET['tab'] ) ); if ( in_array( $requested_tab, $tab_sections, true ) ) { $tab_active = $requested_tab; } } foreach ( $tabs as $key => $tab ) { $tab_section = $tab_sections[ $key ]; $is_active = $tab_section === $tab_active; $section_tab['tabs'] .= sprintf( '%s', $is_active ? 'is-active' : '', esc_attr( $tab_section ), esc_html( $tab['title'] ?? '' ) ); /** * @uses html_tab_overview * @uses html_tab_settings */ $section_content['content'] .= sprintf( '
%s
', $is_active ? '' : 'lp-hidden', esc_attr( $tab_section ), $tab['html'] ?? '' ); } return Template::combine_components( [ 'tabs' => Template::combine_components( $section_tab ), 'contents' => Template::combine_components( $section_content ), ] ); } public function html_tab_overview( array $data = [] ): string { wp_enqueue_script( 'lp-course-builder' ); $question_model = $data['questionModel'] ?? false; $question_id = $data['item_id'] ?? ( $question_model ? $question_model->get_id() : CourseBuilder::POST_NEW ); if ( absint( $question_id ) && ! $question_model ) { $question_model = QuestionPostModel::find( absint( $question_id ), true ); if ( empty( $question_model ) ) { return ''; } } $html_assigned = $this->assigned_quiz( $question_model ); $html_edit_title = $this->edit_title( $question_model ); $html_permalink = $this->edit_permalink( $question_model ); $html_publish = $this->edit_publish( $question_model ); $html_edit_desc = $this->edit_desc( $question_model ); $section = [ 'wrapper' => sprintf( '
', $question_id ), 'content_wrapper' => '
', 'left_column' => '
', 'edit_title' => $html_edit_title, 'assigned_quiz' => $html_assigned, 'edit_permalink' => $html_permalink, 'edit_publish' => $html_publish, 'left_column_end' => '
', 'right_column' => '
', 'edit_desc' => $html_edit_desc, 'right_column_end' => '
', 'content_wrapper_end' => '
', 'wrapper_end' => '
', ]; return Template::combine_components( $section ); } public function html_tab_settings( array $data = [] ): string { wp_enqueue_style( 'lp-edit-question' ); $question_model = $data['questionModel'] ?? false; $question_id = $data['item_id'] ?? ( $question_model ? $question_model->get_id() : CourseBuilder::POST_NEW ); if ( $question_id === CourseBuilder::POST_NEW || absint( $question_id ) <= 0 ) { return sprintf( '%s', __( 'Please save Question before setting question', 'learnpress' ) ); } if ( ! $question_model ) { $question_model = QuestionPostModel::find( absint( $question_id ), true ); if ( empty( $question_model ) ) { return ''; } } $settings = AdminEditQuestionTemplate::instance()->html_edit_question( $question_model ); $output = [ 'wrapper' => sprintf( '
', $question_id ), 'form_setting' => '
', 'settings' => $settings, 'form_setting_end' => '
', 'wrapper_end' => '
', ]; return Template::combine_components( $output ); } /** * Allow callback for AJAX. * @use self::render_edit_course_curriculum * @use self::render_html * * @param array $callbacks * * @return array */ public function allow_callback( array $callbacks ): array { $callbacks[] = AdminEditCurriculumTemplate::class . ':render_edit_course_curriculum'; return $callbacks; } public function assigned_quiz( $question_model ) { $assign_question = ! empty( $question_model ) ? $this->get_assigned_question( $question_model->get_id() ) : ''; $html_quizzes = ''; $assigned = sprintf( '%s', __( 'Not assigned yet', 'learnpress' ) ); if ( ! empty( $assign_question ) ) { $quizzes = is_array( $assign_question ) && isset( $assign_question['id'] ) ? array( $assign_question ) : $assign_question; $quiz_htmls = array(); foreach ( $quizzes as $quiz ) { $quiz_id = $quiz['id'] ?? 0; $quiz_title = $quiz['title'] ?? ''; if ( $quiz_id && $quiz_title ) { $quiz_link = BuilderQuizTemplate::instance()->get_link_edit( $quiz_id ); $quiz_htmls[] = sprintf( '%s', esc_url( $quiz_link ), esc_html( $quiz_title ) ); } } if ( ! empty( $quiz_htmls ) ) { $assigned = implode( ', ', $quiz_htmls ); } } $html_quizzes = sprintf( '
%s %s
', __( 'Assigned', 'learnpress' ), $assigned ); return $html_quizzes; } public function edit_title( $question_model ) { $title = ! empty( $question_model ) ? $question_model->get_the_title() : ''; $edit = [ 'wrapper' => '
', 'label' => sprintf( '', __( 'Title', 'learnpress' ) ), 'input' => sprintf( '', esc_attr( $title ) ), 'wrapper_end' => '
', ]; return Template::combine_components( $edit ); } /** * @param QuestionPostModel|false $question_model * @return string */ public function edit_desc( $question_model ) { $desc = ! empty( $question_model ) ? $question_model->post_content : ''; $editor_id = 'question_description_editor'; $editor_settings = array( 'textarea_name' => 'question_description', 'textarea_rows' => 10, 'teeny' => false, 'media_buttons' => true, 'tinymce' => array( 'content_style' => "body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif; font-size: 14px; line-height: 1.6; color: #1e1e1e; }", 'toolbar1' => 'formatselect,bold,italic,underline,bullist,numlist,blockquote,alignleft,aligncenter,alignright,link,unlink,spellchecker,wp_adv', 'toolbar2' => 'strikethrough,hr,forecolor,pastetext,removeformat,charmap,outdent,indent,undo,redo,wp_help', ), 'quicktags' => true, ); $edit = [ 'wrapper' => '
', 'label' => sprintf( '', __( 'Description', 'learnpress' ) ), 'edit' => AdminTemplate::editor_tinymce( $desc, $editor_id, $editor_settings ), 'wrapper_end' => '
', ]; return Template::combine_components( $edit ); } public function edit_permalink( $question_model ): string { $post_id = ! empty( $question_model ) ? absint( $question_model->get_id() ) : 0; if ( ! $post_id ) { return Template::combine_components( [ 'wrapper' => '', ] ); } $post = get_post( $post_id ); $post_name = $post ? $post->post_name : ''; $full_url = urldecode( (string) get_permalink( $post_id ) ); $display_data = $this->get_question_display_permalink_data( $post_id, (string) $post_name ); $display_url = (string) ( $display_data['url'] ?? '' ); $editor_slug = (string) ( $display_data['slug'] ?? '' ); if ( empty( $display_url ) ) { $display_url = $full_url; } if ( empty( $full_url ) ) { $full_url = $display_url; } if ( empty( $editor_slug ) ) { $editor_slug = (string) $post_name; } if ( empty( $editor_slug ) && ! empty( $display_url ) ) { $display_path = parse_url( $display_url, PHP_URL_PATH ); if ( is_string( $display_path ) && '' !== $display_path ) { $editor_slug = basename( untrailingslashit( $display_path ) ); } } if ( empty( $full_url ) ) { return Template::combine_components( [ 'wrapper' => '', ] ); } $base_url = $display_url; if ( ! empty( $editor_slug ) && false === strpos( $display_url, '?p=' ) && false === strpos( $display_url, '&p=' ) && false === strpos( $display_url, '?lp_question=' ) && false === strpos( $display_url, '&lp_question=' ) ) { $base_url = trailingslashit( preg_replace( '/' . preg_quote( $editor_slug, '/' ) . '\/?$/', '', $display_url ) ); } $state_a = sprintf( '%s ', __( 'Permalink', 'learnpress' ), esc_url( $full_url ), esc_html( $display_url ), __( 'Edit', 'learnpress' ) ); $state_b = sprintf( '', esc_html( $base_url ), esc_attr( $editor_slug ), esc_attr__( 'your-slug', 'learnpress' ), __( 'OK', 'learnpress' ), __( 'Cancel', 'learnpress' ) ); $hidden_base = sprintf( '', esc_attr( $base_url ) ); $view = [ 'wrapper' => '', ]; return Template::combine_components( $view ); } /** * Get permalink display URL in publish-style format for editing slug. * * @param int $post_id * @param string $post_name * * @return array */ private function get_question_display_permalink_data( int $post_id, string $post_name = '' ): array { $display_url = urldecode( (string) get_permalink( $post_id ) ); $sample_slug = $post_name; if ( ! function_exists( 'get_sample_permalink' ) ) { require_once ABSPATH . 'wp-admin/includes/post.php'; } if ( function_exists( 'get_sample_permalink' ) ) { $sample_permalink = get_sample_permalink( $post_id ); if ( is_array( $sample_permalink ) && ! empty( $sample_permalink[0] ) ) { $sample_slug = ! empty( $sample_permalink[1] ) ? (string) $sample_permalink[1] : $sample_slug; $display_url = str_replace( [ '%postname%', '%pagename%' ], $sample_slug, (string) $sample_permalink[0] ); } } return [ 'url' => urldecode( $display_url ), 'slug' => urldecode( (string) $sample_slug ), ]; } public function edit_publish( $question_model ): string { $post_id = ! empty( $question_model ) ? absint( $question_model->get_id() ) : 0; $post = $post_id ? get_post( $post_id ) : null; $current_status = $post && ! empty( $post->post_status ) ? sanitize_key( $post->post_status ) : 'draft'; $status_value = 'draft' === $current_status ? 'draft' : 'publish'; $status_options_html = sprintf( '', selected( $status_value, 'publish', false ), esc_html__( 'Published', 'learnpress' ), selected( $status_value, 'draft', false ), esc_html__( 'Draft', 'learnpress' ) ); $publish = [ 'wrapper' => '
', 'title' => sprintf( '

%s

', esc_html__( 'Publish', 'learnpress' ) ), 'status_row' => sprintf( '
', esc_html__( 'Status', 'learnpress' ), $status_options_html ), 'wrapper_end' => '
', ]; return Template::combine_components( $publish ); } public function get_assigned_question( $id ) { $curd = new LP_Question_CURD(); $quiz = $curd->get_quiz( $id ); if ( $quiz ) { return array( 'id' => $quiz->ID, 'title' => $quiz->post_title ?? '', ); } return false; } }