Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add attendee survey to wordcamps. #997

Merged
Merged
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
151c60f
Add the attendence survey to wordcamp with event network urls.
StevenDufresne Aug 4, 2023
31d02ae
Probably don't need valid url check.
StevenDufresne Aug 4, 2023
b7e00c0
Add survey plugin.
StevenDufresne Aug 4, 2023
88eeabd
Remove code that was added to new site, prefer plugin.
StevenDufresne Aug 4, 2023
e789546
Make sure attendee survey is network activated.
StevenDufresne Aug 4, 2023
6853dfb
Remove useless code.
StevenDufresne Aug 4, 2023
1b1e716
Trim content for now.
StevenDufresne Aug 4, 2023
eb59992
Revert "Make sure attendee survey is network activated."
StevenDufresne Aug 4, 2023
a13748d
Revert "Revert "Make sure attendee survey is network activated.""
StevenDufresne Aug 4, 2023
5d1213d
Render menu item.
StevenDufresne Aug 4, 2023
548cd90
Fix formatting error.
StevenDufresne Aug 4, 2023
dbdef69
Delete survery stub.
StevenDufresne Aug 4, 2023
fa9d8ac
Refactor to split by deature.
StevenDufresne Aug 7, 2023
7a34c49
more stuff
StevenDufresne Aug 8, 2023
bcf5e97
Update cron function name.
StevenDufresne Aug 8, 2023
4969c09
Bunch of stuff :)
StevenDufresne Aug 10, 2023
2e145e0
Revert the add_filter that was commented out.
StevenDufresne Aug 10, 2023
0788ba1
ADd a function that interfaces with the camptix log.
StevenDufresne Aug 10, 2023
0035826
Improve the doc blocks.
StevenDufresne Aug 10, 2023
30bb11f
Improve log message.
StevenDufresne Aug 11, 2023
5332304
Revert "Improve log message."
StevenDufresne Aug 11, 2023
17bfa43
Add comment.
StevenDufresne Aug 11, 2023
256f437
Improve error message for cron job.
StevenDufresne Aug 11, 2023
d85b5d5
Update function name to be more clear.
StevenDufresne Aug 11, 2023
d78ede5
Update the to include a TODO.
StevenDufresne Aug 11, 2023
6c6adbe
Localize admin page strings.
StevenDufresne Aug 11, 2023
a83f53c
Switch query to look fro closed wordcamps.
StevenDufresne Aug 11, 2023
6fa71ee
Add some links to the attende survey view.
StevenDufresne Aug 11, 2023
aee4a02
We don't need to check if it's already associated to email.
StevenDufresne Aug 16, 2023
bae6c80
Revert "We don't need to check if it's already associated to email."
StevenDufresne Aug 16, 2023
1bf4814
Remove the check for adding recipients.
StevenDufresne Aug 16, 2023
bfc7ee0
Update the function name.
StevenDufresne Aug 16, 2023
9a42483
Change to look at whether its greater or equal to 2 days than just one.
StevenDufresne Aug 16, 2023
6557822
Update email content.
StevenDufresne Aug 28, 2023
cf75cad
Allow the ability to activity on a specific site.
StevenDufresne Aug 28, 2023
338a921
Check the values better when calculating sent.
StevenDufresne Aug 28, 2023
ea3c714
Only suggest we turn on attendee survey for events.
StevenDufresne Aug 28, 2023
093d557
Disable the page 2 weeks later.
StevenDufresne Aug 30, 2023
dab7600
Update the activate references.
StevenDufresne Aug 30, 2023
3b44be1
Refocus the cron that unpublishes the page.
StevenDufresne Aug 30, 2023
0a1fdd4
only queues cron and add a page if it's an event.
StevenDufresne Aug 30, 2023
f086b8c
Update the form markup.
StevenDufresne Sep 1, 2023
5acdee8
Remove empty line.
StevenDufresne Sep 1, 2023
d19de33
Add an empty view to admin.
StevenDufresne Sep 1, 2023
af29c86
Update the comment.
StevenDufresne Sep 1, 2023
b444446
Remove activation sequence since it will process itself on init.
StevenDufresne Sep 1, 2023
ef2ea8f
Make function name consistent.
StevenDufresne Sep 4, 2023
01ed96f
Remove tests.
StevenDufresne Sep 4, 2023
1578442
Run linter.
StevenDufresne Sep 4, 2023
fe22789
Rename to camptix attendee survey.
StevenDufresne Sep 4, 2023
20f2751
Fix email example copy.
StevenDufresne Sep 4, 2023
f72f387
Update cron to daily.
StevenDufresne Sep 6, 2023
f446ba2
Update conditional inclusion logic for plugin.
StevenDufresne Sep 6, 2023
8d4df83
Remove the email on the form, it will default to admin email.
StevenDufresne Sep 6, 2023
1c312e1
Use top level domain to make the event test response environment.
StevenDufresne Sep 7, 2023
6d9a3d3
Update the doc block for get_feedback_details.
StevenDufresne Sep 7, 2023
8306d9e
Prefer using the site id.
StevenDufresne Sep 7, 2023
b567296
Remove the skip feature.
StevenDufresne Sep 8, 2023
57073be
Remove the cron job after sucessfully queing everything.
StevenDufresne Sep 11, 2023
78c0a7a
Update the site id language.
StevenDufresne Sep 13, 2023
11c757a
Only try to send 2 days later to prevent going back in time.
StevenDufresne Sep 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ function _get_network_plugin_state_list( $state ) {
$network_plugin_state['activated'][] = 'tagregator/bootstrap.php';
} elseif ( EVENTS_NETWORK_ID === $network_id ) {
$network_plugin_state['deactivated'][] = 'tagregator/bootstrap.php';
$network_plugin_state['activated'][] = 'camptix-attendee-survey/camptix-attendee-survey.php';
}

return $network_plugin_state[ $state ];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<?php
/**
* Plugin Name: CampTix Attendee Survey
* Plugin URI: https://wordcamp.org
* Description: Send survey to WordCamp attendees.
* Author: WordCamp.org
* Author URI: https://wordcamp.org
* Version: 1
*
* @package CampTix\AttendeeSurvey
*/

namespace CampTix\AttendeeSurvey;

use function CampTix\AttendeeSurvey\Email\{add_email, delete_email};
use function CampTix\AttendeeSurvey\Page\{add_page, delete_page};

defined( 'WPINC' ) || die();

/**
* Local dependencies.
*/
require_once get_includes_path() . 'email.php';
require_once get_includes_path() . 'page.php';

/**
* Plugin activation and deactivation hooks.
*/
register_deactivation_hook( __FILE__, __NAMESPACE__ . '\deactivate' );

/**
* Actions & hooks
*/
add_action( 'plugins_loaded', __NAMESPACE__ . '\load' );

/**
* Get the ID of the survey feature.
*/
function get_feature_id() {
return 'attendee_survey';
}

/**
* Check dependencies for loading the plugin.
*
* @return bool
*/
function can_load() {
$skip_feature = wcorg_skip_feature( get_feature_id() );

return ! $skip_feature;
}

/**
* Include the rest of the plugin.
*
* @return void
*/
function load() {
if ( ! can_load() ) {
return;
}

// We only want to admin panel on central, nothing else.
if ( WORDCAMP_ROOT_BLOG_ID === get_current_blog_id() ) {
require_once get_includes_path() . 'admin-page.php';
}

if ( is_wordcamp_type( 'next-gen' ) ) {
require_once get_includes_path() . 'cron.php';
add_action( 'init', __NAMESPACE__ . '\activate_on_current_site' );
}
}

/**
* The activation routine for a single site.
*
* @return void
*/
function activate_on_current_site() {
add_page();
add_email();

// Flushing the rewrite rules is buggy in the context of `switch_to_blog`.
// The rules will automatically get recreated on the next request to the site.
delete_option( 'rewrite_rules' );
}

/**
* Remove the survey page.
*
* @param bool $is_network True if deactivating network-wide.
*
* @return void
*/
function deactivate( $is_network = false ) {
if ( $is_network ) {
deactivate_on_network();
} else {
deactivate_on_current_site();
}
}

/**
* Run the deactivation routine on all valid sites in the network.
*
* @return void
*/
function deactivate_on_network() {
$valid_sites = get_site_ids_without_skip_flag();

foreach ( $valid_sites as $blog_id ) {
switch_to_blog( $blog_id );
deactivate_on_current_site();
restore_current_blog();
}
}

/**
* The deactivation routine for a single site.
*
* @return void
*/
function deactivate_on_current_site() {
delete_page();
delete_email();
}

/**
* Get the IDs of sites that do not have the FEATURE_ID skip feature flag.
*
* @return array
*/
function get_site_ids_without_skip_flag() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we've needed this here and in the Speaker Feedback plugin, I think it makes sense to extract it into a generic function in mu-plugins/wp-cli-commands/miscellaneous.php, next to set_skip_feature_flag().

That way any plugin can use it, rather than duplicating it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also wondered about just removing it since we're limiting it to events and this survey will probably apply across the board.

I think I'll remove it. Yep.

global $wpdb;

$blog_ids = $wpdb->get_col(
$wpdb->prepare("
SELECT b.blog_id
FROM $wpdb->blogs AS b
LEFT OUTER JOIN $wpdb->blogmeta AS m
ON b.blog_id = m.blog_id AND m.meta_key = 'wordcamp_skip_feature' AND m.meta_value = %s
WHERE m.meta_value IS NULL
",
get_feature_id()
)
);

return array_map( 'absint', $blog_ids );
}

/**
* Shortcut to the includes directory.
*
* @return string
*/
function get_includes_path() {
return plugin_dir_path( __FILE__ ) . 'includes/';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
<?php
/**
* Adds a page to the central admin.
*/

namespace CampTix\AttendeeSurvey\AdminPage;

defined( 'WPINC' ) || die();

use CampTix_Plugin;

use function CampTix\AttendeeSurvey\{get_feature_id};
use function CampTix\AttendeeSurvey\Email\{get_email_id};
use function CampTix\AttendeeSurvey\Page\{get_page_id};
use function CampTix\AttendeeSurvey\Cron\{get_wordcamp_attendees_id};

add_action( 'init', __NAMESPACE__ . '\init' );

/**
* Registered the appropriate filters and actions.
*/
function init() {
add_action( 'admin_menu', __NAMESPACE__ . '\admin_menu' );
}

/**
* Add a menu item.
*/
function admin_menu() {
add_menu_page(
__( 'WordCamp Attendee Survey', 'wordcamporg' ),
__( 'Attendee Survey', 'wordcamporg' ),
'manage_options',
get_feature_id(),
__NAMESPACE__ . '\render_menu_page',
'dashicons-feedback',
58
);
}

/**
* Get stats for each feedback for all sites.
*
* @return array[] An array of custom elements.
* Each element has the following structure:
* [
* 'title' => string,
* 'sent' => string,
* 'responses' => string,
* 'rate' => string,
* ]
*/
function get_feedback_details() {
/* @var CampTix_Plugin $camptix */
global $camptix;

$wordcamps = get_posts( array(
'post_type' => WCPT_POST_TYPE_ID,
'post_status' => 'wcpt-closed',
'posts_per_page' => -1,
) );

$feedback_details = array();

foreach ( $wordcamps as $camp ) {
$site_id = get_post_meta( $camp->ID, '_site_id', true );

switch_to_blog( $site_id );

$blog_details = get_blog_details( $site_id );

// TODO: This should be tested elsewhere.
if ( 'events.wordpress.test' !== $blog_details->domain ) {
continue;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this'll need to be updated to work on production.

You could use get_top_level_domain() in place of a hardcoded .test, but I think it'd be a bit more clear to check if $site->blog_id === EVENTS_NETWORK_ID.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. Makes sense.


$query = new \WP_Query( array(
'post_type' => 'feedback',
'post_parent' => get_page_id(),
'posts_per_page' => -1,
) );

$sent = (int) $camptix->get_sent_email_count( get_email_id() );
$responses = (int) $query->found_posts;

$feedback_details[] = array(
'title' => $blog_details->blogname,
'admin_url' => admin_url(),
'email_url' => get_edit_post_link( get_email_id() ),
'responses_url' => admin_url( sprintf( 'edit.php?post_type=feedback&jetpack_form_parent_id=%s', get_page_id() ) ),
'sent' => $sent,
'responses' => $responses,
'rate' => 0 !== $sent ? ( $responses / $sent ) * 100 . '%' : '',
);

// Restore the original site context.
restore_current_blog();
}

// Reset the global post object.
wp_reset_postdata();

return $feedback_details;
}

/**
* Render the menu page.
*/
function render_menu_page() {
?>
<div class="wrap">
<h1><?php echo esc_html__( 'Attendee Survey', 'wordcamporg' ); ?></h1>

<table class="wp-list-table widefat fixed striped table-view-list">
<thead>
<tr>
<td><?php esc_html_e( 'Event', 'wordcamporg' ); ?></td>
<td><?php esc_html_e( 'Total Sent', 'wordcamporg' ); ?></td>
<td><?php esc_html_e( 'Total Responses', 'wordcamporg' ); ?></td>
<td><?php esc_html_e( 'Response rate', 'wordcamporg' ); ?></td>
</tr>
</thead>
<tbody>
<?php
$feedback_details = get_feedback_details();

foreach ( $feedback_details as $feedback_detail ) {
echo '<tr>';
echo '<td><a href="'. esc_url( $feedback_detail['admin_url'] ) . '">' . esc_html( $feedback_detail['title'] ) . '</a></td>';
echo '<td><a href="'. esc_url( $feedback_detail['email_url'] ) . '">' . esc_html( $feedback_detail['sent'] ) . '</a></td>';
echo '<td><a href="'. esc_url( $feedback_detail['responses_url'] ) . '">' . esc_html( $feedback_detail['responses'] ) . '</a></td>';
echo '<td>' . esc_html( $feedback_detail['rate'] ) . '</td>';
echo '</tr>';
}

if ( empty( $feedback_details ) ) {
echo '<tr><td colspan="4">' . esc_html__( 'Nothing to report', 'wordcamporg' ) . '</td></tr>';
}

?>
</tbody>
</table>
</div>
<?php
}
Loading
Loading