• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bleedingdeacons / confur / 31015112238

05 Aug 2026 02:25PM UTC coverage: 95.194% (-0.1%) from 95.299%
31015112238

push

github

web-flow
chore(tooling): make PSR-12 a gate and badge the standard (#50)

* chore(tooling): exclude WordPress and test-only sniffs from PSR-12

Groundwork for making PHPCS a gate. No formatting changes here - this commit
only narrows the ruleset, adds the .gitattributes this repo was missing, and
promotes the CI step, so the reformatting that follows is reviewable on its
own.

* style: reindent with spaces and give five methods a visibility keyword

This plugin was tab-indented throughout while the rest of the suite is not,
which accounted for 2,116 of its findings across 18 files - more than a
quarter of the whole suite's. phpcbf did that reindent plus the usual
structural tidying: opening braces onto their own line, inline
if (...) { return x; } expanded, multi-line call arguments aligned,
trailing blank lines before closing braces dropped.

Not purely whitespace, so git diff -w on this commit is not empty. The
non-whitespace part is the brace and inline-control-structure restructuring
above, plus five methods that were declared with no visibility keyword and
a snake_case name:

  AcfHelper::update_acf_field   -> public static function updateAcfField
  AcfHelper::update_acf_fields  -> public static function updateAcfFields
  AcfHelper::update_acf_field2  -> public static function updateAcfField2
  AnswerShortcode::get_field    -> public function getField
  AnswerShortcode::get_the_ID   -> public function getTheId

The AcfHelper three are called only from their own tests and one commented
line in AnswerHandler; both were updated. The AnswerShortcode two are thin
wrappers that exist so the global ACF/WP calls can be swapped out in tests -
they kept their // Calls global comments, and their two internal callers
in the same class were updated. No behaviour changes.

Two file-level docblocks in GeneralShortcodes and HtmlHelper sat between a
class_exists() guard and the class they describe, which PSR-12 reads as a
misplaced file docblock. Each moved inside its gua... (continued)

1022 of 1111 new or added lines in 21 files covered. (91.99%)

3 existing lines in 3 files now uncovered.

2258 of 2372 relevant lines covered (95.19%)

4.08 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.54
/src/Shortcodes/AnswerShortcode.php
1
<?php
2

3
namespace Confur\Shortcodes;
4

5
use Confur\Config\Constants;
6
use Confur\Repositories\AnswerRepository;
7

8
/**
9
 * Answer-related shortcodes
10
 */
11
class AnswerShortcode
12
{
13
    private AnswerRepository $answerRepository;
14

15
    public function __construct()
24 ✔
16
    {
17
        $this->answerRepository = new AnswerRepository();
24 ✔
18
    }
19

20
    /**
21
     * @param string $selector
22
     * @param int|string|false $post_id
23
     * @param bool $format_value
24
     * @return mixed ACF returns whatever the field holds.
25
     */
26
    public function getField($selector, $post_id = false, $format_value = true)
4 ✔
27
    {
28
        return \get_field($selector, $post_id, $format_value);  // Calls global
4 ✔
29
    }
30

31
    /**
32
     * @return int|false Post ID, or false outside the loop.
33
     */
NEW
34
    public function getTheId()
×
35
    {
NEW
36
        return \get_the_ID();  // Calls global
×
37
    }
38

39
    /**
40
     * Generate answer field
41
     *
42
     * @param array<string, mixed> $atts Shortcode attributes
43
     * @return string Rendered HTML
44
     */
45
    /**
46
     * Generate answer field
47
     *
48
     * @param array<string, mixed> $atts Shortcode attributes
49
     * @return string Rendered HTML
50
     */
51
    public function generateAnswerField(array $atts = []): string
6 ✔
52
    {
53
        $committee = isset($atts['committee']) ? sanitize_text_field($atts['committee']) : '';
6 ✔
54
        $question = isset($atts['question']) ? sanitize_text_field($atts['question']) : '';
6 ✔
55
        $hidden = isset($atts['hidden']) && filter_var($atts['hidden'], FILTER_VALIDATE_BOOLEAN);
6 ✔
56

57
        $name = 'c' . esc_attr($committee) . '_a' . esc_attr($question);
6 ✔
58

59
        $existingValue = $this->answerRepository->getValue($name);
6 ✔
60
        $safeValue = !empty($existingValue) ? esc_textarea($existingValue) : '';
6 ✔
61

62
        $labelText = $hidden
6 ✔
63
            ? sprintf('Answer %s', esc_html($question))
1 ✔
64
            : sprintf('Answer %s.%s', esc_html($committee), esc_html($question));
5 ✔
65

66
        $label = sprintf(
6 ✔
67
            '<label class="answer" for="%s">%s</label>',
6 ✔
68
            esc_attr($name),
6 ✔
69
            $labelText
6 ✔
70
        );
6 ✔
71

72
        $textarea = sprintf(
6 ✔
73
            '<textarea class="answer" name="%s" id="%s" placeholder="">%s</textarea>',
6 ✔
74
            esc_attr($name),
6 ✔
75
            esc_attr($name),
6 ✔
76
            $safeValue
6 ✔
77
        );
6 ✔
78

79
        $textareaExisting = sprintf(
6 ✔
80
            '<textarea class="existing-answer" id="e_%s" readonly>%s</textarea>',
6 ✔
81
            esc_attr($name),
6 ✔
82
            $safeValue
6 ✔
83
        );
6 ✔
84

85
        return $label . $textarea . $textareaExisting;
6 ✔
86
    }
87

88
    /**
89
     * Generate question
90
     *
91
     * @param array<string, mixed> $atts Shortcode attributes
92
     * @param string|null $content Shortcode content
93
     * @return string Rendered HTML
94
     */
95
    public function generateQuestion(array $atts = [], ?string $content = null): string
4 ✔
96
    {
97
        $question = trim($atts['number']);
4 ✔
98
        $committee = trim($atts['committee']);
4 ✔
99
        $hidden = isset($atts['hidden']) && filter_var($atts['hidden'], FILTER_VALIDATE_BOOLEAN);
4 ✔
100

101
        $name = 'c' . $committee . '_q' . $question;
4 ✔
102
        $content = do_shortcode($content);
4 ✔
103

104
        $headerText = $hidden
4 ✔
105
            ? sprintf('Question %s', $question)
1 ✔
106
            : sprintf('Question %s.%s', $committee, $question);
3 ✔
107

108
        return sprintf(
4 ✔
109
            '<h3 id="%s">%s</h3>%s',
4 ✔
110
            $name,
4 ✔
111
            $headerText,
4 ✔
112
            $content
4 ✔
113
        );
4 ✔
114
    }
115

116
    /**
117
     * Generate committee
118
     *
119
     * @param array<string, mixed> $atts Shortcode attributes
120
     * @param string|null $content Shortcode content
121
     * @return string Rendered HTML
122
     */
123
    public function generateCommittee(array $atts = [], ?string $content = null): string
2 ✔
124
    {
125
        $number = sanitize_text_field(trim($atts['number']));
2 ✔
126
        $id = 'c' . $number;
2 ✔
127

128
        // Check if name attribute exists, otherwise use default "Committee {number}"
129
        $title = isset($atts['name']) ? sanitize_text_field(trim($atts['name'])) : 'Committee ' . $number;
2 ✔
130

131
        $content = do_shortcode($content);
2 ✔
132

133
        return sprintf(
2 ✔
134
            '<div id="g_%s"><h2>%s</h2>%s</div>',
2 ✔
135
            $id,
2 ✔
136
            $title,
2 ✔
137
            $content
2 ✔
138
        );
2 ✔
139
    }
140

141
    /**
142
     * Generate start committee
143
     *
144
     * @param array<string, mixed> $atts Shortcode attributes
145
     * @return string Rendered HTML
146
     */
147
    public function generateStartCommittee(array $atts = []): string
1 ✔
148
    {
149
        $number = trim($atts['number']);
1 ✔
150
        $id = 'c' . $number;
1 ✔
151

152
        return sprintf(
1 ✔
153
            '<div id="%s"><h2>Committee %s</h2>',
1 ✔
154
            $id,
1 ✔
155
            $number
1 ✔
156
        );
1 ✔
157
    }
158

159
    /**
160
     * Generate end committee
161
     *
162
     * @return string Rendered HTML
163
     */
164
    public function generateEndCommittee(): string
1 ✔
165
    {
166
        return '</div>';
1 ✔
167
    }
168

169
    /**
170
     * Generate header
171
     *
172
     * @return string Rendered HTML
173
     */
174
    public function generateHeader(): string
2 ✔
175
    {
176
        $meetingId = get_field(Constants::MEETING_FIELD);
2 ✔
177
        $fellow_meetingId = get_field(Constants::FELLOW_MEETING_FIELD);
2 ✔
178
        $meetingTitle = get_the_title($meetingId);
2 ✔
179

180
        if (! empty($fellow_meetingId)) {
2 ✔
181
            $meetingTitle .= ' and ' . get_the_title($fellow_meetingId);
1 ✔
182
        }
183

184
        return sprintf(
2 ✔
185
            '<h2>Answers from %s</h2>',
2 ✔
186
            esc_html($meetingTitle)
2 ✔
187
        );
2 ✔
188
    }
189

190
    /**
191
     * Configure custom form
192
     *
193
     * @param array<string, mixed> $atts Shortcode attributes
194
     * @return string Rendered HTML
195
     */
196
    public function configureCustomForm(array $atts): string
1 ✔
197
    {
198
        error_log('Action: ' . $atts['action']);
1 ✔
199

200
        return sprintf(
1 ✔
201
            '<input type="hidden" name="action" value="%s">',
1 ✔
202
            esc_attr($atts['action'])
1 ✔
203
        );
1 ✔
204
    }
205

206
    /**
207
     * Generate status
208
     *
209
     * @param array<string, mixed> $atts Shortcode attributes
210
     * @return string Rendered HTML
211
     */
212
    public function generateStatus(array $atts): string
1 ✔
213
    {
214
        return sprintf(
1 ✔
215
            '<p class="middle important" id="%sDirty">You have made unsaved changes!</p>',
1 ✔
216
            esc_attr($atts['position'])
1 ✔
217
        );
1 ✔
218
    }
219

220
    /**
221
     * Generate progress table
222
     *
223
     * @return string Rendered HTML
224
     */
225
    public function generateProgressTable(): string
1 ✔
226
    {
227
        $html = '<div id="progress">';
1 ✔
228
        $html .= '<table><tbody>';
1 ✔
229

230
        for ($count = 1; $count <= 6; $count++) {
1 ✔
231
            $html .= sprintf(
1 ✔
232
                '<tr><td><a href="#g_c%1$d" class="status-link"><strong>Committee %1$d</a></strong></td><td class="value" id="s_c%1$d">Not Started</td></tr>',
1 ✔
233
                $count
1 ✔
234
            );
1 ✔
235
        }
236

237
        // Work around for extra questions not grouped by 'Committee'
238
        $count = 7;
1 ✔
239
        $html .= sprintf(
1 ✔
240
            '<tr><td><a href="#g_c%1$d" class="status-link"><strong>All Committees</a></strong></td><td class="value" id="s_c%1$d">Not Started</td></tr>',
1 ✔
241
            $count
1 ✔
242
        );
1 ✔
243

244
        $html .= '</tbody></table></div>';
1 ✔
245

246
        return $html;
1 ✔
247
    }
248

249
    /**
250
     * Generate control
251
     *
252
     * @param array<string, mixed> $atts Shortcode attributes
253
     * @return string Rendered HTML
254
     */
255
    public function generateControl(array $atts): string
1 ✔
256
    {
257
        $position = esc_attr($atts['position']);
1 ✔
258

259
        $html = sprintf('<div><strong>Status: </strong><span id="%sSaveState"></span></div>', $position);
1 ✔
260
        $html .= sprintf('<div><strong>Last Saved: </strong><span id="%sSaveTime"></span></div>', $position);
1 ✔
261
        $html .= '<div id="buttons">';
1 ✔
262
        $html .= sprintf(
1 ✔
263
            '<button type="button" class="submit" id="%sSubmit" name="submit_answers" value="Draft" disabled>Save Draft</button>',
1 ✔
264
            $position
1 ✔
265
        );
1 ✔
266
        $html .= sprintf(
1 ✔
267
            '<button type="button" class="submit" id="%sFinish" name="submit_answers" value="Complete" disabled>Save Complete</button>',
1 ✔
268
            $position
1 ✔
269
        );
1 ✔
270
        $html .= '</div>';
1 ✔
271

272
        return $html;
1 ✔
273
    }
274

275
    /**
276
     * Generate allocated committee display
277
     *
278
     * Displays "Allocated Committee (Number)" if the associated meeting
279
     * has a populated allocation field. Committee 7 displays as "Final Committee".
280
     *
281
     * @param array<string, mixed> $atts Shortcode attributes
282
     * @return string Rendered HTML or empty string if no allocation
283
     */
284
    public function generateAllocatedCommittee(array $atts = []): string
4 ✔
285
    {
286
        // Get the meeting ID from the current answer post
287
        $meetingId = $this->getField(Constants::MEETING_FIELD);
4 ✔
288

289
        if (empty($meetingId)) {
4 ✔
290
            return '';
1 ✔
291
        }
292

293
        // Get the allocation field from the meeting
294
        // Assumes Constants::ALLOCATION_FIELD exists, adjust field name as needed
295
        $allocation = $this->getField(Constants::ALLOCATION_FIELD, $meetingId);
3 ✔
296

297
        if (empty($allocation)) {
3 ✔
298
            return '';
1 ✔
299
        }
300

301
        // Sanitize the allocation value
302
        $committeeNumber = is_numeric($allocation) ? intval($allocation) : sanitize_text_field($allocation);
2 ✔
303

304
        // Committee 7 is displayed as "Last Question"
305
        if ($committeeNumber === 7) {
2 ✔
306
            return sprintf(
1 ✔
307
                '<p class="allocated-committee">To start, your group has been allocated: <a href="#g_c%1$d" class="status-link">Last Question</a> (Under All Committee\'s)</p>',
1 ✔
308
                $committeeNumber
1 ✔
309
            );
1 ✔
310
        }
311

312
        return sprintf(
1 ✔
313
            '<p class="allocated-committee">To start, your group has been allocated: <a href="#g_c%1$d" class="status-link">Committee %1$d</a></p>',
1 ✔
314
            $committeeNumber
1 ✔
315
        );
1 ✔
316
    }
317
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc