616 lines
16 KiB
PHP
616 lines
16 KiB
PHP
<?php
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Surveys Controller class.
|
|
*
|
|
* Handles API calls related to Surveys
|
|
*
|
|
* @since 1.0.0
|
|
*
|
|
* @package UserFeedback
|
|
* @author David Paternina
|
|
*/
|
|
class UserFeedback_Surveys {
|
|
|
|
public function __construct() {
|
|
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
|
|
add_action( 'in_admin_footer', [ $this, 'promote_userfeedback' ] );
|
|
}
|
|
|
|
/**
|
|
* Registers REST routes
|
|
*
|
|
* @return void
|
|
*/
|
|
public function register_routes() {
|
|
|
|
register_rest_route(
|
|
'userfeedback/v1',
|
|
'/surveys',
|
|
array(
|
|
'methods' => 'GET',
|
|
'callback' => array( $this, 'get_surveys' ),
|
|
'permission_callback' => array( $this, 'create_edit_surveys_permission_check' ),
|
|
'args' => array(
|
|
'filter' => array(
|
|
'type' => 'object',
|
|
'sanitize_callback' => array( $this, 'sanitize_filter_param' ),
|
|
),
|
|
'orderby' => array(
|
|
'type' => 'string',
|
|
'sanitize_callback' => array( $this, 'sanitize_orderby_param' ),
|
|
),
|
|
'order' => array(
|
|
'type' => 'string',
|
|
'sanitize_callback' => array( $this, 'sanitize_order_param' ),
|
|
),
|
|
'select' => array(
|
|
'type' => 'array',
|
|
'sanitize_callback' => array( $this, 'sanitize_select_param' ),
|
|
),
|
|
'page' => array(
|
|
'type' => 'integer',
|
|
'sanitize_callback' => 'absint',
|
|
),
|
|
'per_page' => array(
|
|
'type' => 'integer',
|
|
'sanitize_callback' => 'absint',
|
|
),
|
|
),
|
|
)
|
|
);
|
|
|
|
register_rest_route(
|
|
'userfeedback/v1',
|
|
'/surveys/(?P<id>\w+)',
|
|
array(
|
|
'methods' => 'GET',
|
|
'callback' => array( $this, 'get_survey' ),
|
|
'permission_callback' => array( $this, 'create_edit_surveys_permission_check' ),
|
|
)
|
|
);
|
|
|
|
register_rest_route(
|
|
'userfeedback/v1',
|
|
'/surveys',
|
|
array(
|
|
'methods' => 'POST',
|
|
'callback' => array( $this, 'save_survey' ),
|
|
'permission_callback' => array( $this, 'create_edit_surveys_permission_check' ),
|
|
)
|
|
);
|
|
|
|
register_rest_route(
|
|
'userfeedback/v1',
|
|
'/surveys/restore',
|
|
array(
|
|
'methods' => 'POST',
|
|
'callback' => array( $this, 'restore_surveys' ),
|
|
'permission_callback' => array( $this, 'delete_surveys_permission_check' ),
|
|
)
|
|
);
|
|
|
|
register_rest_route(
|
|
'userfeedback/v1',
|
|
'/surveys/draft',
|
|
array(
|
|
'methods' => 'POST',
|
|
'callback' => array( $this, 'draft_surveys' ),
|
|
'permission_callback' => array( $this, 'create_edit_surveys_permission_check' ),
|
|
)
|
|
);
|
|
|
|
register_rest_route(
|
|
'userfeedback/v1',
|
|
'/surveys/trash',
|
|
array(
|
|
'methods' => 'POST',
|
|
'callback' => array( $this, 'trash_surveys' ),
|
|
'permission_callback' => array( $this, 'delete_surveys_permission_check' ),
|
|
)
|
|
);
|
|
|
|
register_rest_route(
|
|
'userfeedback/v1',
|
|
'/surveys/publish',
|
|
array(
|
|
'methods' => 'POST',
|
|
'callback' => array( $this, 'publish_surveys' ),
|
|
'permission_callback' => array( $this, 'create_edit_surveys_permission_check' ),
|
|
)
|
|
);
|
|
|
|
register_rest_route(
|
|
'userfeedback/v1',
|
|
'/surveys',
|
|
array(
|
|
'methods' => 'DELETE',
|
|
'callback' => array( $this, 'delete_surveys' ),
|
|
'permission_callback' => array( $this, 'delete_surveys_permission_check' ),
|
|
)
|
|
);
|
|
|
|
register_rest_route(
|
|
'userfeedback/v1',
|
|
'/surveys/(?P<id>\w+)/duplicate',
|
|
array(
|
|
'methods' => 'POST',
|
|
'callback' => array( $this, 'duplicate_survey' ),
|
|
'permission_callback' => array( $this, 'create_edit_surveys_permission_check' ),
|
|
)
|
|
);
|
|
|
|
register_rest_route(
|
|
'userfeedback/v1',
|
|
'/survey-templates',
|
|
array(
|
|
'methods' => 'GET',
|
|
'callback' => array( $this, 'get_available_survey_templates' ),
|
|
'permission_callback' => array( $this, 'create_edit_surveys_permission_check' ),
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Permissions Check
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function create_edit_surveys_permission_check() {
|
|
return current_user_can( 'userfeedback_create_edit_surveys' );
|
|
}
|
|
|
|
/**
|
|
* Permissions Check
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function delete_surveys_permission_check() {
|
|
return current_user_can( 'userfeedback_delete_surveys' );
|
|
}
|
|
|
|
/**
|
|
* Sanitize filter parameter to prevent SQL injection
|
|
*
|
|
* @param mixed $filters
|
|
* @return array
|
|
*/
|
|
public function sanitize_filter_param( $filters ) {
|
|
if ( ! is_array( $filters ) ) {
|
|
return array();
|
|
}
|
|
|
|
// Only 'status' and 'type' are valid filter attributes for surveys
|
|
$allowed_filter_attrs = array( 'status', 'type' );
|
|
$sanitized = array();
|
|
|
|
foreach ( $filters as $key => $value ) {
|
|
// Only allow whitelisted column names
|
|
$sanitized_key = sanitize_key( $key );
|
|
if ( in_array( $sanitized_key, $allowed_filter_attrs, true ) ) {
|
|
$sanitized[ $sanitized_key ] = sanitize_text_field( $value );
|
|
}
|
|
}
|
|
|
|
return $sanitized;
|
|
}
|
|
|
|
/**
|
|
* Sanitize orderby parameter to prevent SQL injection
|
|
*
|
|
* @param string $orderby
|
|
* @return string
|
|
*/
|
|
public function sanitize_orderby_param( $orderby ) {
|
|
// Allowed columns from UserFeedback_Survey::get_columns()
|
|
$allowed_orderby = array( 'id', 'title', 'status', 'type', 'impressions', 'publish_at', 'created_at' );
|
|
|
|
$orderby = sanitize_key( $orderby );
|
|
|
|
return in_array( $orderby, $allowed_orderby, true ) ? $orderby : 'id';
|
|
}
|
|
|
|
/**
|
|
* Sanitize order parameter
|
|
*
|
|
* @param string $order
|
|
* @return string
|
|
*/
|
|
public function sanitize_order_param( $order ) {
|
|
$order = strtolower( sanitize_key( $order ) );
|
|
return in_array( $order, array( 'asc', 'desc' ), true ) ? $order : 'desc';
|
|
}
|
|
|
|
/**
|
|
* Sanitize select parameter to prevent SQL injection
|
|
*
|
|
* @param mixed $select
|
|
* @return array
|
|
*/
|
|
public function sanitize_select_param( $select ) {
|
|
if ( ! is_array( $select ) ) {
|
|
return array( '*' );
|
|
}
|
|
|
|
// Allowed columns from UserFeedback_Survey::get_columns()
|
|
$allowed_columns = array( 'id', 'title', 'status', 'type', 'questions', 'settings', 'notifications', 'impressions', 'publish_at', 'created_at' );
|
|
$sanitized = array();
|
|
|
|
foreach ( $select as $column ) {
|
|
$sanitized_column = sanitize_key( $column );
|
|
if ( in_array( $sanitized_column, $allowed_columns, true ) ) {
|
|
$sanitized[] = $sanitized_column;
|
|
}
|
|
}
|
|
|
|
return ! empty( $sanitized ) ? $sanitized : array( '*' );
|
|
}
|
|
|
|
/**
|
|
* Get Surveys
|
|
*
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function get_surveys( WP_REST_Request $request ) {
|
|
$has_pagination = false;
|
|
|
|
$query = UserFeedback_Survey::where(
|
|
array(
|
|
array( 'status', '!=', 'trash' ), // Get only published and drafts by default
|
|
)
|
|
)->with_count( array( 'responses' ) );
|
|
|
|
if ( $request->has_param( 'filter' ) ) {
|
|
$filters = $request->get_param( 'filter' );
|
|
|
|
// Sanitization callback should have already cleaned this,
|
|
// but add defensive check for safety
|
|
if ( ! is_array( $filters ) ) {
|
|
$filters = array();
|
|
}
|
|
|
|
foreach ( $filters as $attr => $value ) {
|
|
if ( $value === 'all' ) {
|
|
break;
|
|
}
|
|
|
|
if ( $attr === 'status' && $value === 'publish' ) {
|
|
$query->add_where(
|
|
array(
|
|
'status' => 'publish',
|
|
'publish_at' => null,
|
|
),
|
|
true
|
|
)->or_where(
|
|
array(
|
|
'status' => 'publish',
|
|
array( 'publish_at', '<=', current_time( 'mysql', true ) ),
|
|
)
|
|
);
|
|
} elseif ( $attr === 'status' && $value === 'scheduled' ) {
|
|
$query->add_where(
|
|
array(
|
|
'status' => 'publish',
|
|
array( 'publish_at', 'is not', null ),
|
|
array( 'publish_at', '>', current_time( 'mysql', true ) ),
|
|
),
|
|
true
|
|
);
|
|
} else {
|
|
// Only 'status' and 'type' should reach here due to sanitization
|
|
$query->add_where(
|
|
array(
|
|
$attr => $value,
|
|
),
|
|
true
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( $request->has_param( 'orderby' ) ) {
|
|
$field = $request->get_param( 'orderby' );
|
|
$order = $request->get_param( 'order' );
|
|
$order = $order ?: 'desc';
|
|
|
|
$query->sort( $field, $order );
|
|
} else {
|
|
$query->sort( 'id', 'desc' );
|
|
}
|
|
|
|
if ( $request->has_param( 'select' ) ) {
|
|
$query->select( $request->get_param( 'select' ) );
|
|
}
|
|
|
|
if ( $request->has_param( 'page' ) ) {
|
|
$has_pagination = true;
|
|
$query->paginate(
|
|
$request->has_param( 'per_page' ) ? $request->get_param('per_page') : 10,
|
|
$request->get_param( 'page' )
|
|
);
|
|
}
|
|
|
|
$surveys = $query->get();
|
|
|
|
if ( ! $has_pagination ) {
|
|
return new WP_REST_Response( $surveys );
|
|
}
|
|
|
|
// Data for quick filters
|
|
$count_by_status_result = UserFeedback_Survey::query()
|
|
->select( array( 'status', 'count' ) )
|
|
->select_raw( 'if (publish_at is null or publish_at <= now(), false, true) as scheduled' )
|
|
->group_by( 'status, scheduled' )
|
|
->get();
|
|
|
|
$allTotal = 0;
|
|
|
|
foreach ( $count_by_status_result as $item ) {
|
|
if ( $item->status !== 'trash' ) {
|
|
$allTotal += $item->count;
|
|
}
|
|
|
|
if ( $item->status === 'publish' && $item->scheduled ) {
|
|
$item->status = 'scheduled';
|
|
}
|
|
|
|
unset( $item->scheduled );
|
|
}
|
|
|
|
array_unshift(
|
|
$count_by_status_result,
|
|
array(
|
|
'status' => 'all',
|
|
'count' => $allTotal,
|
|
)
|
|
);
|
|
|
|
$surveys['status_filters'] = $count_by_status_result;
|
|
|
|
return new WP_REST_Response( $surveys );
|
|
}
|
|
|
|
/**
|
|
* Get a single survey by id
|
|
*
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function get_survey( WP_REST_Request $request ) {
|
|
|
|
$survey_id = $request->get_param( 'id' );
|
|
|
|
$survey = UserFeedback_Survey::find( $survey_id );
|
|
|
|
if ( ! $survey ) {
|
|
return new WP_REST_Response( null, 404 );
|
|
}
|
|
|
|
if ( $request->has_param( 'with' ) ) {
|
|
$query_instance = UserFeedback_Survey::query();
|
|
$query_instance->with( explode( ',', $request->get_param( 'with' ) ) );
|
|
$survey = $query_instance->populate_relations( $survey );
|
|
}
|
|
|
|
return new WP_REST_Response(
|
|
$survey
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Saves or updates a Survey
|
|
*
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function save_survey( WP_REST_Request $request ) {
|
|
|
|
// Check if params include id
|
|
$survey_id = $request['id'];
|
|
|
|
if ( userfeedback_is_tracking_allowed() && isset( $request['template'] ) ) {
|
|
$tracked_data = get_option( 'userfeedback_tracking_data', array() );
|
|
|
|
if ( isset( $tracked_data['templates'] ) ) {
|
|
$tracked_data['templates'][] = $request['template'];
|
|
} else {
|
|
$tracked_data['templates'] = array(
|
|
$request['template'],
|
|
);
|
|
}
|
|
|
|
update_option( 'userfeedback_tracking_data', $tracked_data );
|
|
}
|
|
|
|
$params = $request->get_params();
|
|
$params = apply_filters('userfeedback_save_survey_params', $params, $survey_id);
|
|
$survey_count = UserFeedback_Survey::count();
|
|
|
|
if(isset($params['title']) && 'First Survey' === $params['title'] && $survey_count > 0) {
|
|
unset($params['title']);
|
|
UserFeedback_Survey::update( $survey_id, $params );
|
|
$survey = UserFeedback_Survey::get_by( 'title', 'First Survey' );
|
|
$survey_id = $survey->id;
|
|
$params['title'] = 'First Survey';
|
|
}
|
|
|
|
if ( isset( $survey_id ) && $survey_id != 'null' ) {
|
|
UserFeedback_Survey::update( $survey_id, $params );
|
|
$survey = UserFeedback_Survey::find( $survey_id );
|
|
} else {
|
|
$number_of_surveys = UserFeedback_Survey::count();
|
|
// translators: %d is the survey number.
|
|
$new_survey_title = empty( $params['title'] ) ? sprintf( __( 'Survey #%d', 'userfeedback-lite' ), $number_of_surveys + 1 ) : $params['title'];
|
|
|
|
/**
|
|
* Add type for nps surveys
|
|
* Surveys created from the template `nps` is marked as NPS survey
|
|
*/
|
|
if (
|
|
! isset( $survey_id ) &&
|
|
isset( $params[ 'template' ] ) &&
|
|
'nps' === $params[ 'template' ]
|
|
) {
|
|
$params['type'] = 'nps';
|
|
}
|
|
|
|
$new_id = UserFeedback_Survey::create(
|
|
array_merge(
|
|
$params,
|
|
array( 'title' => $new_survey_title )
|
|
)
|
|
);
|
|
$survey = UserFeedback_Survey::find( $new_id );
|
|
}
|
|
|
|
return new WP_REST_Response( $survey );
|
|
}
|
|
|
|
/**
|
|
* Duplicate survey with the given id
|
|
*
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function duplicate_survey( $data ) {
|
|
|
|
$survey_id = $data['id'];
|
|
$survey = UserFeedback_Survey::find( $survey_id );
|
|
|
|
// Save as new survey, return new one's id
|
|
unset( $survey->id );
|
|
$new_survey_id = UserFeedback_Survey::create(
|
|
array_merge(
|
|
(array) $survey,
|
|
array(
|
|
// translators: %s is the original survey title.
|
|
'title' => sprintf( __( 'Copy of %s', 'userfeedback-lite' ), $survey->title ),
|
|
'status' => 'draft',
|
|
)
|
|
)
|
|
);
|
|
|
|
$new_survey = UserFeedback_Survey::find( $new_survey_id );
|
|
|
|
return new WP_REST_Response(
|
|
$new_survey
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Restore surveys by Id
|
|
*
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function restore_surveys( $data ) {
|
|
$survey_ids = $data['survey_ids'];
|
|
UserFeedback_Survey::restore( $survey_ids );
|
|
return new WP_REST_Response( null, 204 );
|
|
}
|
|
|
|
/**
|
|
* Draft surveys by Id
|
|
*
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function draft_surveys( $data ) {
|
|
$survey_ids = $data['survey_ids'];
|
|
$temp = UserFeedback_Survey::draft( $survey_ids );
|
|
return new WP_REST_Response( $temp, 200 );
|
|
}
|
|
|
|
/**
|
|
* Publish surveys by Id
|
|
*
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function publish_surveys( $data ) {
|
|
$survey_ids = $data['survey_ids'];
|
|
$temp = UserFeedback_Survey::publish( $survey_ids );
|
|
return new WP_REST_Response( $temp, 200 );
|
|
}
|
|
|
|
/**
|
|
* Trash surveys by Id
|
|
*
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function trash_surveys( $data ) {
|
|
$survey_ids = $data['survey_ids'];
|
|
UserFeedback_Survey::trash( $survey_ids );
|
|
return new WP_REST_Response( null, 204 );
|
|
}
|
|
|
|
/**
|
|
* Delete surveys by Id
|
|
*
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function delete_surveys( $data ) {
|
|
$survey_ids = $data['survey_ids'];
|
|
UserFeedback_Survey::delete( $survey_ids );
|
|
return new WP_REST_Response( null, 204 );
|
|
}
|
|
|
|
/**
|
|
* Get available Survey templates
|
|
*
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function get_available_survey_templates() {
|
|
$templates = UserFeedback_Survey_Templates::get_instance()->get_available_templates();
|
|
return new WP_REST_Response( $templates );
|
|
}
|
|
|
|
/**
|
|
* Pre-footer promotion block, displayed on all WPForms admin pages except Form Builder.
|
|
*/
|
|
public function promote_userfeedback() {
|
|
$is_uf_page = userfeedback_screen_is_userfeedback();
|
|
|
|
if( !$is_uf_page ){
|
|
return;
|
|
}
|
|
|
|
$is_pro = userfeedback_is_pro_version();
|
|
|
|
$links = [
|
|
[
|
|
'text' => __( 'Support', 'userfeedback-lite' ),
|
|
'link' => $is_pro ? userfeedback_get_url('footer_link', 'made-with-love', 'https://www.userfeedback.com/contact/') : 'https://wordpress.org/support/plugin/userfeedback-lite/',
|
|
'target' => '_blank',
|
|
],
|
|
[
|
|
'text' => __( 'Docs', 'userfeedback-lite' ),
|
|
'link' => userfeedback_get_url('footer_link', 'made-with-love', 'https://www.userfeedback.com/docs/'),
|
|
'target' => '_blank',
|
|
],
|
|
[
|
|
'text' => __( 'Free Plugins', 'userfeedback-lite' ),
|
|
'link' => admin_url('admin.php?page=userfeedback_settings#/about'),
|
|
'target' => '_self',
|
|
],
|
|
[
|
|
'text' => __( 'Suggest a Feature', 'userfeedback-lite' ),
|
|
'link' => userfeedback_get_url('footer_link', 'made-with-love', 'https://www.userfeedback.com/suggest-feature/'),
|
|
'target' => '_blank',
|
|
],
|
|
];
|
|
if(!empty($links)){
|
|
echo '<div class="userfeedback-love">';
|
|
echo esc_html__('Made with ♥ by the UserFeedback Team', 'userfeedback-lite');
|
|
$links_output = [];
|
|
foreach($links as $link){
|
|
$links_output[] = '<a target="'.esc_attr($link['target']).'" href="'.esc_url($link['link']).'">' . esc_html($link['text']) . '</a>';
|
|
}
|
|
echo wp_kses_post( '<div>' . implode( '<span class="sep">/</span>', $links_output ) . '</div>' );
|
|
echo '</div>';
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
new UserFeedback_Surveys();
|