PluginProbe
Parse.ly / 3.24.2
Parse.ly v3.24.2
3.24.3 3.24.2 3.24.1 3.24.0 3.23.7 3.23.6 3.23.5 3.23.4 3.23.3 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.17.0 3.18.0 3.18.1 3.19.0 3.19.1 3.19.2 3.19.3 3.2.0 3.2.1 3.20.0 3.20.1 All 107 releases
← All changes | src/UI/class-settings-page.php +161 -2 3.23.4 → 3.24.2 View file →
@@ -10,8 +10,9 @@
10 10
11 11 namespace Parsely\UI;
12 12
13 13 use Parsely\Content_Helper\Excerpt_Suggestions;
14 +use Parsely\Content_Helper\Suggestion_Defaults;
14 15 use Parsely\Parsely;
15 16 use Parsely\Permissions;
16 17 use Parsely\Utils\Utils;
17 18 use Parsely\Validator;
@@ -77,9 +78,12 @@
77 78 * }
78 79 *
79 80 * @phpstan-type Parsely_Settings_Options_Content_Helper_Feature array{
80 81 * enabled?: bool,
81 - * allowed_user_roles?: array<string, string>|array<string, bool>
82 + * allowed_user_roles?: array<string, string>|array<string, bool>,
83 + * default_length?: mixed,
84 + * default_tone?: mixed,
85 + * default_persona?: mixed
82 86 * }
83 87 *
84 88 * @phpstan-import-type Parsely_Options from Parsely
85 89 * @phpstan-import-type Parsely_Options_Headline_Testing from Parsely
@@ -110,8 +114,21 @@
110 114 */
111 115 private $managed_options_badge = array();
112 116
113 117 /**
118 + * The Content Intelligence features that expose site-wide generation
119 + * defaults in the settings page.
120 + *
121 + * @since 3.24.0
122 + *
123 + * @var string[]
124 + */
125 + private const FEATURES_WITH_DEFAULTS = array(
126 + 'title_suggestions',
127 + 'excerpt_suggestions',
128 + );
129 +
130 + /**
114 131 * The Content Intelligence features that can be configured in the settings
115 132 * page.
116 133 *
117 134 * @since 3.16.0
@@ -1121,12 +1138,110 @@
1121 1138 }
1122 1139
1123 1140 echo '</fieldset>';
1124 1141
1142 + if ( in_array( $feature_id, self::FEATURES_WITH_DEFAULTS, true ) ) {
1143 + $this->print_suggestion_defaults( $args, $options, $feature_id );
1144 + }
1145 +
1125 1146 $this->print_filter_text( $args );
1126 1147 }
1127 1148
1128 1149 /**
1150 + * Prints out a feature's site-wide generation defaults.
1151 + *
1152 + * These apply to users who have not yet set their own values in the editor.
1153 + * The desired length is printed for Excerpt Suggestions only, as Title
1154 + * Suggestions has no equivalent setting.
1155 + *
1156 + * @since 3.24.0
1157 + *
1158 + * @param Setting_Arguments $args The arguments for the fieldset.
1159 + * @param Parsely_Options $options The plugin's options.
1160 + * @param string $feature_id The feature's name.
1161 + */
1162 + private function print_suggestion_defaults( $args, $options, string $feature_id ): void {
1163 + /** @var array<string, mixed> $feature_options */
1164 + $feature_options = $options['content_helper'][ $feature_id ] ?? array();
1165 + $is_managed = key_exists( 'content_helper', $this->parsely->managed_options );
1166 +
1167 + echo '<fieldset class="', esc_attr( str_replace( '_', '-', $feature_id ) ), '-defaults"',
1168 + $is_managed ? ' disabled>' : '>';
1169 + echo '<legend class="screen-reader-text"><span>';
1170 + printf(
1171 + /* translators: %s: Feature name */
1172 + esc_html__( '%s Default Settings', 'wp-parsely' ),
1173 + esc_html( $args['legend'] ?? __( 'Feature', 'wp-parsely' ) )
1174 + );
1175 + echo '</span></legend>';
1176 +
1177 + if ( Excerpt_Suggestions::get_feature_name() === $feature_id ) {
1178 + $length_key = $args['option_key'] . '[default_length]';
1179 + printf(
1180 + '<p><label for="%1$s">%2$s</label><br />' .
1181 + '<input type="number" name="%3$s" id="%1$s" value="%4$d" min="%5$d" max="%6$d" step="1" class="small-text" /></p>',
1182 + esc_attr( $length_key ),
1183 + esc_html__( 'Default length (characters)', 'wp-parsely' ),
1184 + esc_attr( $this->get_html_name_attribute( $length_key ) ),
1185 + absint( Suggestion_Defaults::get_default_length( $feature_options ) ),
1186 + absint( Suggestion_Defaults::MIN_LENGTH ),
1187 + absint( Suggestion_Defaults::MAX_LENGTH )
1188 + );
1189 + }
1190 +
1191 + $this->print_suggestion_defaults_select(
1192 + $args['option_key'] . '[default_tone]',
1193 + __( 'Default tone', 'wp-parsely' ),
1194 + Suggestion_Defaults::get_tones(),
1195 + Suggestion_Defaults::get_default_tone( $feature_options )
1196 + );
1197 +
1198 + $this->print_suggestion_defaults_select(
1199 + $args['option_key'] . '[default_persona]',
1200 + __( 'Default persona', 'wp-parsely' ),
1201 + Suggestion_Defaults::get_personas(),
1202 + Suggestion_Defaults::get_default_persona( $feature_options )
1203 + );
1204 +
1205 + echo '</fieldset>';
1206 + }
1207 +
1208 + /**
1209 + * Prints out a select tag for a feature's default generation setting.
1210 + *
1211 + * @since 3.24.0
1212 + *
1213 + * @param string $option_key The nested option key.
1214 + * @param string $label The visible label.
1215 + * @param array<string, string> $choices The choices, as value => label pairs.
1216 + * @param string $selected The currently selected value.
1217 + */
1218 + private function print_suggestion_defaults_select(
1219 + string $option_key,
1220 + string $label,
1221 + array $choices,
1222 + string $selected
1223 + ): void {
1224 + printf(
1225 + '<p><label for="%1$s">%2$s</label><br /><select name="%3$s" id="%1$s">',
1226 + esc_attr( $option_key ),
1227 + esc_html( $label ),
1228 + esc_attr( $this->get_html_name_attribute( $option_key ) )
1229 + );
1230 +
1231 + foreach ( $choices as $value => $choice_label ) {
1232 + printf(
1233 + '<option value="%s"%s>%s</option>',
1234 + esc_attr( $value ),
1235 + selected( $selected, $value, false ),
1236 + esc_html( $choice_label )
1237 + );
1238 + }
1239 +
1240 + echo '</select></p>';
1241 + }
1242 +
1243 + /**
1129 1244 * Prints out the select tags
1130 1245 *
1131 1246 * @param Setting_Arguments $args The arguments for the select dropdowns.
1132 1247 */
@@ -1557,11 +1672,55 @@
1557 1672 }
1558 1673
1559 1674 // Produce the final array.
1560 1675 $options = $this->parsely->get_options()['content_helper'];
1561 - $merged = array_merge( $options, $input['content_helper'] );
1562 1676
1677 + // Validate the generation defaults separately, as the sanitizer above
1678 + // coerces every scalar into a boolean. Values that were not submitted
1679 + // fall back to the stored ones, and anything invalid falls back to the
1680 + // shipped default.
1681 + $validated_defaults = array();
1682 + foreach ( self::FEATURES_WITH_DEFAULTS as $feature_id ) {
1683 + /** @var array<string, mixed> $submitted */
1684 + $submitted = $input['content_helper'][ $feature_id ] ?? array();
1685 + /** @var array<string, mixed> $stored */
1686 + $stored = $options[ $feature_id ];
1687 +
1688 + $defaults = array(
1689 + 'default_tone' => Suggestion_Defaults::get_default_tone(
1690 + array( 'default_tone' => $submitted['default_tone'] ?? $stored['default_tone'] ?? null )
1691 + ),
1692 + 'default_persona' => Suggestion_Defaults::get_default_persona(
1693 + array( 'default_persona' => $submitted['default_persona'] ?? $stored['default_persona'] ?? null )
1694 + ),
1695 + );
1696 +
1697 + // Only Excerpt Suggestions has a desired length.
1698 + if ( Excerpt_Suggestions::get_feature_name() === $feature_id ) {
1699 + $length = $submitted['default_length'] ?? $stored['default_length'] ?? null;
1700 +
1701 + // Anything that is not an integer is invalid, rather than
1702 + // something to coerce into one.
1703 + $length = is_scalar( $length ) ? filter_var( $length, FILTER_VALIDATE_INT ) : false;
1704 +
1705 + $defaults['default_length'] = Suggestion_Defaults::get_default_length(
1706 + array( 'default_length' => false === $length ? null : $length )
1707 + );
1708 + }
1709 +
1710 + $validated_defaults[ $feature_id ] = $defaults;
1711 + }
1712 +
1713 + $merged = array_merge( $options, $input['content_helper'] );
1714 +
1563 1715 $input['content_helper'] = $sanitize( $merged );
1716 +
1717 + foreach ( $validated_defaults as $feature_id => $defaults ) {
1718 + $input['content_helper'][ $feature_id ] = array_merge(
1719 + $input['content_helper'][ $feature_id ],
1720 + $defaults
1721 + );
1722 + }
1564 1723
1565 1724 return $input;
1566 1725 }
1567 1726