I was just looking at Megiddo's code example above. I believe his won't break ulx commands unless they include some of those censored words (such as in the name of the player or the reason provided for ban/kick).
You're always returning WordC/text, modified or not.
Gmod chat hooks will always stop other hooks from functioning if anything but nil is returned. (as we've discussed)
However, Megiddo uses a 'return' if nothing was found/edited, or the modified text if something was.
You can use his, or make slight modification to yours code that would look like the following
WordD = { "word1" , "word2" }
function WFilter( ply, text, toall )
local WordC = nil
for _, v in ipairs( WordD ) do
if string.find( text, v, 1, true) then
WordC = string.Replace(text,v,"****")
end
end
if WordC then return WordC else return end
end
hook.Add( "PlayerSay", "WFilter", WFilter )
In that code, WordC always gets set to nil everytime something is said.
If a censored word is found, it gets set in WordC. If not, WordC remains nil.
After it loops, if WordC has text, it is returned censored. If not, the hook is returned nothing, which should allow other scripts, such as ULX, to see the chat.